org.jfree.util.ObjectTable Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcommon Show documentation
Show all versions of jcommon Show documentation
JCommon is a free general purpose Java class library that is used in
several projects at www.jfree.org, including JFreeChart and
JFreeReport.
/* ========================================================================
* JCommon : a free general purpose class library for the Java(tm) platform
* ========================================================================
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ----------------
* ObjectTable.java
* ----------------
* (C) Copyright 2003, 2004, by Object Refinery Limited.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: ObjectTable.java,v 1.10 2008/09/10 09:22:04 mungady Exp $
*
* Changes
* -------
* 29-Apr-2003 : Version 1, based on PaintTable class (DG);
* 21-May-2003 : Copied the array based implementation of StrokeTable and
* fixed the serialisation behaviour (TM).
*/
package org.jfree.util;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
/**
* A lookup table for objects. This implementation is not synchronized, it is up
* to the caller to synchronize it properly.
*
* @author Thomas Morgner
*/
public class ObjectTable implements Serializable
{
/**
* For serialization.
*/
private static final long serialVersionUID = -3968322452944912066L;
/**
* The number of rows.
*/
private int rows;
/**
* The number of columns.
*/
private int columns;
/**
* An array of objects. The array may contain null
values.
*/
private transient Object[][] data;
/**
* Defines how many object-slots get reserved each time we run out of
* space.
*/
private int rowIncrement;
/**
* Defines how many object-slots get reserved each time we run out of
* space.
*/
private int columnIncrement;
/**
* Creates a new table.
*/
public ObjectTable()
{
this(5, 5);
}
/**
* Creates a new table.
*
* @param increment the row and column size increment.
*/
public ObjectTable(final int increment)
{
this(increment, increment);
}
/**
* Creates a new table.
*
* @param rowIncrement the row size increment.
* @param colIncrement the column size increment.
*/
public ObjectTable(final int rowIncrement, final int colIncrement)
{
if (rowIncrement < 1)
{
throw new IllegalArgumentException("Increment must be positive.");
}
if (colIncrement < 1)
{
throw new IllegalArgumentException("Increment must be positive.");
}
this.rows = 0;
this.columns = 0;
this.rowIncrement = rowIncrement;
this.columnIncrement = colIncrement;
this.data = new Object[rowIncrement][];
}
/**
* Returns the column size increment.
*
* @return the increment.
*/
public int getColumnIncrement()
{
return this.columnIncrement;
}
/**
* Returns the row size increment.
*
* @return the increment.
*/
public int getRowIncrement()
{
return this.rowIncrement;
}
/**
* Checks that there is storage capacity for the specified row and resizes
* if necessary.
*
* @param row the row index.
*/
protected void ensureRowCapacity(final int row)
{
// does this increase the number of rows? if yes, create new storage
if (row >= this.data.length)
{
final Object[][] enlarged = new Object[row + this.rowIncrement][];
System.arraycopy(this.data, 0, enlarged, 0, this.data.length);
// do not create empty arrays - this is more expensive than checking
// for null-values.
this.data = enlarged;
}
}
/**
* Ensures that there is storage capacity for the specified item.
*
* @param row the row index.
* @param column the column index.
*/
public void ensureCapacity(final int row, final int column)
{
if (row < 0)
{
throw new IndexOutOfBoundsException("Row is invalid. " + row);
}
if (column < 0)
{
throw new IndexOutOfBoundsException("Column is invalid. " + column);
}
ensureRowCapacity(row);
final Object[] current = this.data[row];
if (current == null)
{
final Object[] enlarged
= new Object[Math.max(column + 1, this.columnIncrement)];
this.data[row] = enlarged;
}
else if (column >= current.length)
{
final Object[] enlarged = new Object[column + this.columnIncrement];
System.arraycopy(current, 0, enlarged, 0, current.length);
this.data[row] = enlarged;
}
}
/**
* Returns the number of rows in the table.
*
* @return The row count.
*/
public int getRowCount()
{
return this.rows;
}
/**
* Returns the number of columns in the table.
*
* @return The column count.
*/
public int getColumnCount()
{
return this.columns;
}
/**
* Returns the object from a particular cell in the table. Returns null, if
* there is no object at the given position.
*
* Note: throws IndexOutOfBoundsException if row or column is negative.
*
* @param row the row index (zero-based).
* @param column the column index (zero-based).
* @return The object.
*/
protected Object getObject(final int row, final int column)
{
if (row < this.data.length)
{
final Object[] current = this.data[row];
if (current == null)
{
return null;
}
if (column < current.length)
{
return current[column];
}
}
return null;
}
/**
* Sets the object for a cell in the table. The table is expanded if
* necessary.
*
* @param row the row index (zero-based).
* @param column the column index (zero-based).
* @param object the object.
*/
protected void setObject(final int row, final int column,
final Object object)
{
ensureCapacity(row, column);
this.data[row][column] = object;
this.rows = Math.max(this.rows, row + 1);
this.columns = Math.max(this.columns, column + 1);
}
/**
* Tests this paint table for equality with another object (typically also
* an ObjectTable
).
*
* @param o the other object.
* @return A boolean.
*/
public boolean equals(final Object o)
{
if (o == null)
{
return false;
}
if (this == o)
{
return true;
}
if ((o instanceof ObjectTable) == false)
{
return false;
}
final ObjectTable ot = (ObjectTable) o;
if (getRowCount() != ot.getRowCount())
{
return false;
}
if (getColumnCount() != ot.getColumnCount())
{
return false;
}
for (int r = 0; r < getRowCount(); r++)
{
for (int c = 0; c < getColumnCount(); c++)
{
if (ObjectUtilities.equal(getObject(r, c),
ot.getObject(r, c)) == false)
{
return false;
}
}
}
return true;
}
/**
* Returns a hash code value for the object.
*
* @return the hashcode
*/
public int hashCode()
{
int result;
result = this.rows;
result = 29 * result + this.columns;
return result;
}
/**
* Handles serialization.
*
* @param stream the output stream.
* @throws java.io.IOException if there is an I/O problem.
*/
private void writeObject(final ObjectOutputStream stream)
throws IOException
{
stream.defaultWriteObject();
final int rowCount = this.data.length;
stream.writeInt(rowCount);
for (int r = 0; r < rowCount; r++)
{
final Object[] column = this.data[r];
stream.writeBoolean(column != null);
if (column != null)
{
final int columnCount = column.length;
stream.writeInt(columnCount);
for (int c = 0; c < columnCount; c++)
{
writeSerializedData(stream, column[c]);
}
}
}
}
/**
* Handles the serialization of an single element of this table.
*
* @param stream the stream which should write the object
* @param o the object that should be serialized
* @throws IOException if an IO error occured
*/
protected void writeSerializedData(final ObjectOutputStream stream,
final Object o)
throws IOException
{
stream.writeObject(o);
}
/**
* Restores a serialized object.
*
* @param stream the input stream.
* @throws java.io.IOException if there is an I/O problem.
* @throws ClassNotFoundException if a class cannot be found.
*/
private void readObject(final ObjectInputStream stream)
throws IOException, ClassNotFoundException
{
stream.defaultReadObject();
final int rowCount = stream.readInt();
this.data = new Object[rowCount][];
for (int r = 0; r < rowCount; r++)
{
final boolean isNotNull = stream.readBoolean();
if (isNotNull)
{
final int columnCount = stream.readInt();
final Object[] column = new Object[columnCount];
this.data[r] = column;
for (int c = 0; c < columnCount; c++)
{
column[c] = readSerializedData(stream);
}
}
}
}
/**
* Handles the deserialization of a single element of the table.
*
* @param stream the object input stream from which to read the object.
* @return the deserialized object
* @throws ClassNotFoundException if a class cannot be found.
* @throws IOException Any of the usual Input/Output related
* exceptions.
*/
protected Object readSerializedData(final ObjectInputStream stream)
throws ClassNotFoundException, IOException
{
return stream.readObject();
}
/**
* Clears the table.
*/
public void clear()
{
this.rows = 0;
this.columns = 0;
for (int i = 0; i < this.data.length; i++)
{
if (this.data[i] != null)
{
Arrays.fill(this.data[i], null);
}
}
}
/**
* Copys the contents of the old column to the new column.
*
* @param oldColumn the index of the old (source) column
* @param newColumn the index of the new column
*/
protected void copyColumn(final int oldColumn, final int newColumn)
{
for (int i = 0; i < getRowCount(); i++)
{
setObject(i, newColumn, getObject(i, oldColumn));
}
}
/**
* Copys the contents of the old row to the new row. This uses raw access to
* the data and is remarkably faster than manual copying.
*
* @param oldRow the index of the old row
* @param newRow the index of the new row
*/
protected void copyRow(final int oldRow, final int newRow)
{
this.ensureCapacity(newRow, getColumnCount());
final Object[] oldRowStorage = this.data[oldRow];
if (oldRowStorage == null)
{
final Object[] newRowStorage = this.data[newRow];
if (newRowStorage != null)
{
Arrays.fill(newRowStorage, null);
}
}
else
{
this.data[newRow] = (Object[]) oldRowStorage.clone();
}
}
/**
* Sets the table data.
*
* @param data the data.
* @param colCount the number of columns.
*/
protected void setData(final Object[][] data, final int colCount)
{
if (data == null) {
throw new NullPointerException();
}
if (colCount < 0) {
throw new IndexOutOfBoundsException();
}
this.data = data;
this.rows = data.length;
this.columns = colCount;
}
/**
* Returns the table data.
*
* @return The table data.
*/
protected Object[][] getData()
{
return this.data;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy