/*
* @(#) src/net/sf/ivmaidns/util/ConstVector.java --
* Class for immutable vectors for 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.InvalidObjectException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
/**
* Class for immutable vectors for objects.
**
* This <CODE>final</CODE> class is useful for representation of a
* constant vector (container) of custom objects of any type. An
* instance of this class encapsulates/wraps (when constructed) a
* given <CODE>Object</CODE> array. Important notes: the component
* type of the encapsulated <CODE>Object</CODE> array is hidden; an
* object of this class may be serialized only if all custom objects
* it contains are serializable.
**
* @see ConstPair
* @see ObjectVector
* @see GComparator
**
* @version 2.0
* @author Ivan Maidanski
**
* @since 1.2
*/
public final class ConstVector
implements Immutable, ReallyCloneable, Serializable, Indexable,
Sortable, Verifiable
{
/**
* The class version unique identifier for serialization
* interoperability.
**
* @since 1.8
*/
private static final long serialVersionUID = 3843350134190606883L;
/**
* The wrapped (encapsulated) custom array of objects.
**
* <VAR>array</VAR> must be non-<CODE>null</CODE> (but its elements
* may be <CODE>null</CODE>). Important notes:
* <VAR>array[index]</VAR> must not be changed anyhow for every
* <VAR>index</VAR>; the component type of <VAR>array</VAR> is of no
* use here.
**
* @serial
**
* @see ConstVector#ConstVector(java.lang.Object[])
* @see #length()
* @see #getAt(int)
* @see #toArray()
* @see #integrityCheck()
*/
protected final Object[] array;
/**
* Constructs an immutable vector by wrapping a given custom array
* of objects.
**
* Important notes: <VAR>array[index]</VAR> must not be changed
* anyhow for each index (since no cloning is performed for
* <VAR>array</VAR> here).
**
* @param array
* the object array (must be non-<CODE>null</CODE>) to be
* encapsulated.
* @exception NullPointerException
* if <VAR>array</VAR> is <CODE>null</CODE>.
**
* @see #getAt(int)
* @see #toArray()
* @see #equals(java.lang.Object)
* @see #greaterThan(java.lang.Object)
* @see #toString()
*/
public ConstVector(Object[] array)
throws NullPointerException
{
int len;
len = array.length;
this.array = array;
}
/**
* Returns the number of elements in <CODE>this</CODE> vector.
**
* The result is the same as <CODE>length</CODE> of
* <CODE>toArray()</CODE>.
**
* @return
* amount (non-negative value) of elements.
**
* @see #getAt(int)
* @see #toArray()
*/
public int length()
{
return this.array.length;
}
/**
* Returns value of the element at the specified index.
**
* The result is the same as of <CODE>toArray()[index]</CODE>.
**
* @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 ConstVector#ConstVector(java.lang.Object[])
* @see #length()
* @see #toArray()
*/
public Object getAt(int index)
throws ArrayIndexOutOfBoundsException
{
return this.array[index];
}
/**
* Returns a newly created array filled with the values of the
* elements of <CODE>this</CODE> vector.
**
* Here, the result is the exact instance of <CODE>Object[]</CODE>.
**
* @return
* a new array (not <CODE>null</CODE>), containing values of all the
* elements of <CODE>this</CODE> vector.
* @exception OutOfMemoryError
* if there is not enough memory.
**
* @see ConstVector#ConstVector(java.lang.Object[])
* @see #getAt(int)
* @see #length()
* @see #equals(java.lang.Object)
* @see #greaterThan(java.lang.Object)
* @see #toString()
*/
public Object[] toArray()
{
Object[] array, newArray;
int len = (array = this.array).length;
System.arraycopy(array, 0, newArray = new Object[len], 0, len);
return newArray;
}
/**
* Creates and returns a copy of <CODE>this</CODE> object.
**
* Important notes: the encapsulated array is not cloned itself.
**
* @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 ConstVector#ConstVector(java.lang.Object[])
* @see #toArray()
* @see #equals(java.lang.Object)
*/
public Object clone()
{
Object obj;
try
{
if ((obj = super.clone()) instanceof ConstVector && 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> vector 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()
{
Object[] array = this.array;
int code = 0, offset = 0;
Object value;
for (int len = array.length; offset < len;
code = (code << 5) - code)
if ((value = array[offset++]) != null)
code ^= value.hashCode();
return code ^ offset;
}
/**
* 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 vector class and all the
* elements of <CODE>this</CODE> vector are equal to the
* corresponding elements of <VAR>obj</VAR> vector.
**
* @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 #length()
* @see #getAt(int)
* @see #hashCode()
* @see #greaterThan(java.lang.Object)
*/
public boolean equals(Object obj)
{
if (obj != this)
{
if (!(obj instanceof ConstVector))
return false;
int offset;
Object[] otherArray = ((ConstVector)obj).array, array;
if ((array = this.array) != otherArray)
{
if ((offset = array.length) != otherArray.length)
return false;
Object value;
while (offset-- > 0)
if ((value = array[offset]) != null)
{
if (!value.equals(otherArray[offset]))
return false;
}
else if (otherArray[offset] != null)
return false;
}
}
return true;
}
/**
* 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. Vectors are compared in the
* element-by-element manner, starting at index <CODE>0</CODE> and
* at each index elements are compared for equality and the first
* non-equal elements pair is compared through <CODE>INSTANCE</CODE>
* of <CODE>GComparator</CODE> class.
**
* @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)
{
int offset;
Object[] array = this.array, otherArray;
boolean isGreater = false;
if (obj != this && obj instanceof ConstVector &&
(otherArray = ((ConstVector)obj).array) != array)
{
int len = array.length;
if ((offset = otherArray.length) < len)
{
isGreater = true;
len = offset;
}
for (offset = 0; offset < len; offset++)
{
Object value, temp = otherArray[offset];
if ((value = array[offset]) != null && !value.equals(temp) ||
value == null && temp != null)
{
isGreater = GComparator.INSTANCE.greater(value, temp);
break;
}
}
}
return isGreater;
}
/**
* Converts vector to its 'in-line' string representation.
**
* The string representations of the values (if value is
* <CODE>null</CODE> then "null") of <CODE>this</CODE> vector are
* placed into the resulting string in the direct index order,
* delimited by a single space.
**
* @return
* the string representation (not <CODE>null</CODE>) of
* <CODE>this</CODE> object.
* @exception OutOfMemoryError
* if there is not enough memory.
**
* @see ConstVector#ConstVector(java.lang.Object[])
* @see #toArray()
*/
public String toString()
{
Object[] array = this.array;
int offset = 0, len = array.length;
StringBuffer sBuf =
new StringBuffer((len << 2) > 24 ? len << 2 : 24);
if (len > 0)
do
{
Object value;
sBuf.append((value = array[offset]) != null ?
value.toString() : "null");
if (++offset >= len)
break;
sBuf.append(' ');
} while (true);
return new String(sBuf);
}
/**
* Verifies <CODE>this</CODE> object for its integrity.
**
* The elements are not checked. For debug purpose only.
**
* @exception InternalError
* if integrity violation is detected.
**
* @see ConstVector#ConstVector(java.lang.Object[])
**
* @since 2.0
*/
public void integrityCheck()
{
if (this.array == null)
throw new InternalError("array: null");
}
/**
* Deserializes an object of this class from a given stream.
**
* This method is responsible for reading from <VAR>in</VAR> stream,
* restoring the classes fields, and verifying that the serialized
* object is not corrupted. First of all, it calls
* <CODE>defaultReadObject()</CODE> for <VAR>in</VAR> to invoke the
* default deserialization mechanism. Then, it restores the state of
* <CODE>transient</CODE> fields and performs additional
* verification of the deserialized object. This method is used only
* internally by <CODE>ObjectInputStream</CODE> class.
**
* @param in
* the stream (must be non-<CODE>null</CODE>) to read data from in
* order to restore the object.
* @exception NullPointerException
* if <VAR>in</VAR> is <CODE>null</CODE>.
* @exception IOException
* if any I/O error occurs or the serialized object is corrupted.
* @exception ClassNotFoundException
* if the class for an object being restored cannot be found.
* @exception OutOfMemoryError
* if there is not enough memory.
**
* @see ConstVector#ConstVector(java.lang.Object[])
* @see #integrityCheck()
*/
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
if (this.array == null)
throw new InvalidObjectException("array: null");
}
}