/* * @(#) src/net/sf/ivmaidns/util/ConstPair.java -- * Class for immutable pairs of objects. ** * Copyright (c) 2000 Ivan Maidanski <ivmai@mail.ru> * All rights reserved. */ /* * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. ** * This software is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License (GPL) for more details. ** * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. ** * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on this library. If you modify this library, you may extend * this exception to your version of the library, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ package net.sf.ivmaidns.util; import java.io.Serializable; /** * Class for immutable pairs of objects. ** * This instantable class is useful for representation of a constant * sortable pair of custom objects of any type (a container for two * elements). ** * @see ConstVector * @see GComparator ** * @version 2.0 * @author Ivan Maidanski ** * @since 1.2 */ public final class ConstPair implements Immutable, ReallyCloneable, Serializable, Indexable, Sortable { /** * The class version unique identifier for serialization * interoperability. ** * @since 1.8 */ private static final long serialVersionUID = 3724364892682440569L; /** * The first custom object of <CODE>this</CODE> pair. ** * @serial ** * @see ConstPair#ConstPair(java.lang.Object, java.lang.Object) * @see #getAt(int) */ protected final Object valueA; /** * The second custom object of <CODE>this</CODE> pair. ** * @serial ** * @see ConstPair#ConstPair(java.lang.Object, java.lang.Object) * @see #getAt(int) */ protected final Object valueB; /** * Constructs an immutable 'pair' container. ** * @param valueA * the first custom object (may be <CODE>null</CODE>). * @param valueB * the second custom object (may be <CODE>null</CODE>). ** * @see #getAt(int) * @see #equals(java.lang.Object) * @see #greaterThan(java.lang.Object) * @see #toString() */ public ConstPair(Object valueA, Object valueB) { this.valueA = valueA; this.valueB = valueB; } /** * Returns the number of elements in <CODE>this</CODE> container. ** * Here, the result is 2. ** * @return * amount (non-negative value) of elements. ** * @see #getAt(int) */ public int length() { return 2; } /** * Returns value of the element at the specified index. ** * @param index * the index (must be in the range) at which to return an element. * @return * an element (may be <CODE>null</CODE>) at <VAR>index</VAR>. * @exception ArrayIndexOutOfBoundsException * if <VAR>index</VAR> is negative or is not less than * <CODE>length()</CODE>. ** * @see ConstPair#ConstPair(java.lang.Object, java.lang.Object) * @see #length() */ public Object getAt(int index) throws ArrayIndexOutOfBoundsException { if (index >> 1 != 0) throw new ArrayIndexOutOfBoundsException(index); Object value = this.valueA; if (index > 0) value = this.valueB; return value; } /** * Creates and returns a copy of <CODE>this</CODE> object. ** * The result is the same as of * <CODE>new ConstPair(getAt(0), getAt(1))</CODE>. ** * @return * a copy (not <CODE>null</CODE> and != <CODE>this</CODE>) of * <CODE>this</CODE> instance. * @exception OutOfMemoryError * if there is not enough memory. ** * @see ConstPair#ConstPair(java.lang.Object, java.lang.Object) * @see #getAt(int) * @see #equals(java.lang.Object) */ public Object clone() { Object obj; try { if ((obj = super.clone()) instanceof ConstPair && obj != this) return obj; } catch (CloneNotSupportedException e) {} throw new InternalError("CloneNotSupportedException"); } /** * Computes and returns a hash code value for the object. ** * This method hashes all non-<CODE>null</CODE> elements of * <CODE>this</CODE> container and mixes them all to produce a * single hash code value. ** * @return * a hash code value for <CODE>this</CODE> object. ** * @see #length() * @see #getAt(int) * @see #equals(java.lang.Object) */ public int hashCode() { int code = 0; Object value; if ((value = this.valueA) != null) { code = value.hashCode(); code = (code << 5) - code; } if ((value = this.valueB) != null) code ^= value.hashCode(); return ((code << 5) - code) ^ 2; } /** * Indicates whether <CODE>this</CODE> object is equal to the * specified one. ** * This method returns <CODE>true</CODE> if and only if * <VAR>obj</VAR> is instance of this container class and all * elements of <CODE>this</CODE> container are equal to the * corresponding elements of <VAR>obj</VAR>. ** * @param obj * the object (may be <CODE>null</CODE>) with which to compare. * @return * <CODE>true</CODE> if and only if <CODE>this</CODE> value is the * same as <VAR>obj</VAR> value. ** * @see ConstPair#ConstPair(java.lang.Object, java.lang.Object) * @see #length() * @see #getAt(int) * @see #hashCode() * @see #greaterThan(java.lang.Object) */ public boolean equals(Object obj) { boolean isEqual = true; if (obj != this) { isEqual = false; if (obj instanceof ConstPair) { Object value; ConstPair pair = (ConstPair)obj; if ((value = this.valueA) != null && value.equals(pair.valueA) || value == null && pair.valueA == null) if ((value = this.valueB) != null) isEqual = value.equals(pair.valueB); else if (pair.valueB == null) isEqual = true; } } return isEqual; } /** * Tests for being semantically greater than the argument. ** * The result is <CODE>true</CODE> if and only if <VAR>obj</VAR> is * instance of <CODE>this</CODE> class and <CODE>this</CODE> object * is greater than the specified object. Containers are compared in * the element-by-element manner, starting at index <CODE>0</CODE>. * So, the first elements pair is tested for equality and then it * (if equality test has failed) or (else) the second elements pair * is compared through <CODE>INSTANCE</CODE> of * <CODE>GComparator</CODE> class (and the result of this comparison * is returned). ** * @param obj * the second compared object (may be <CODE>null</CODE>). * @return * <CODE>true</CODE> if <VAR>obj</VAR> is comparable with * <CODE>this</CODE> and <CODE>this</CODE> object is greater than * <VAR>obj</VAR>, else <CODE>false</CODE>. ** * @see #length() * @see #getAt(int) * @see #equals(java.lang.Object) ** * @since 1.8 */ public boolean greaterThan(Object obj) { if (obj == this || !(obj instanceof ConstPair)) return false; ConstPair pair = (ConstPair)obj; Object value, pairValue = pair.valueA; if ((value = this.valueA) != null && value.equals(pairValue) || value == null && pairValue == null) { value = this.valueB; pairValue = pair.valueB; } return GComparator.INSTANCE.greater(value, pairValue); } /** * Converts container to its 'in-line' string representation. ** * Here, these two values are placed into the resulting string in * the direct index order, delimited by a single space. ** * @return * the string representation (not <CODE>null</CODE>, with non-zero * <CODE>length()</CODE>) of <CODE>this</CODE> object. * @exception OutOfMemoryError * if there is not enough memory. ** * @see ConstPair#ConstPair(java.lang.Object, java.lang.Object) * @see #length() * @see #getAt(int) */ public String toString() { Object value; return new String((new StringBuffer(24)). append((value = this.valueA) != null ? value.toString() : "null").append(' '). append((value = this.valueB) != null ? value.toString() : "null")); } }