Files
narya/src/java/com/threerings/presents/io/StreamableUtil.java
T
Michael Bayne 1bf6e6093d Added support for streaming arrays of streamables; extracted the efficient
streamable serialization code from PolyStreamableList and made it
generally available; modified the StreamableArrayList to support
heterogenous lists (because they don't have much more overhead than
homogenous lists now) which allows us to remove PolyStreamableList
entirely.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1140 542714f4-19e9-0310-aa3c-eee0fc999fb1
2002-03-20 22:58:26 +00:00

190 lines
5.8 KiB
Java

//
// $Id: StreamableUtil.java,v 1.2 2002/03/20 22:58:26 mdb Exp $
package com.threerings.presents.io;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.Array;
import com.samskivert.io.NestableIOException;
import com.samskivert.util.ListUtil;
/**
* Utility functions useful for {@link Streamable} implementations.
*/
public class StreamableUtil
{
/**
* Writes the supplied int array to the data output stream.
*/
public static void writeInts (DataOutputStream out, int[] values)
throws IOException
{
int vcount = values.length;
out.writeInt(vcount);
for (int i = 0; i < vcount; i++) {
out.writeInt(values[i]);
}
}
/**
* Reads an array of ints from the data input stream that was
* previously written via {@link #writeInts}.
*/
public static int[] readInts (DataInputStream in)
throws IOException
{
int vcount = in.readInt();
int[] values = new int[vcount];
for (int i = 0; i < vcount; i++) {
values[i] = in.readInt();
}
return values;
}
/**
* Writes the supplied string array to the data output stream.
*/
public static void writeStrings (DataOutputStream out, String[] values)
throws IOException
{
int vcount = values.length;
out.writeInt(vcount);
for (int i = 0; i < vcount; i++) {
out.writeUTF(values[i]);
}
}
/**
* Reads an array of strings from the data input stream that was
* previously written via {@link #writeStrings}.
*/
public static String[] readStrings (DataInputStream in)
throws IOException
{
int vcount = in.readInt();
String[] values = new String[vcount];
for (int i = 0; i < vcount; i++) {
values[i] = in.readUTF();
}
return values;
}
/**
* Writes the supplied streamable array to the data output stream. The
* array cannot be null, but can be of zero length.
*/
public static void writeStreamables (
DataOutputStream out, Streamable[] values)
throws IOException
{
// create a list used to map class names to class ids
Object[] cnames = new Object[DEFAULT_SIZE];
// seed it with the component type of the array (which we write
// out first so that we can recreate the array on the other side)
String cname = values.getClass().getComponentType().getName();
cnames[0] = cname;
out.writeUTF(cname);
// write out the size of the list
int size = (values == null) ? 0 : values.length;
out.writeInt(size);
// write out each of the list elements
short nextIdx = 1;
for (int ii = 0; ii < size; ii++) {
// get the next streamable to write out
Streamable s = values[ii];
// look up the class id
cname = s.getClass().getName();
short cidx = (short)ListUtil.indexOfEqual(cnames, cname);
if (cidx == -1) {
// store this class name to class id mapping
cidx = nextIdx++;
cnames = ListUtil.add(cnames, cidx, cname);
// write out the class id and class name
out.writeShort(cidx);
out.writeUTF(cname);
} else {
// we need only write out the class id
out.writeShort(cidx);
}
// write out the object itself
s.writeTo(out);
}
}
/**
* Reads an array of streamables from the data input stream that was
* previously written via {@link #writeStreamables}.
*/
public static Streamable[] readStreamables (DataInputStream in)
throws IOException
{
// read in the component type and array size
String ctype = in.readUTF();
int size = in.readInt();
Streamable[] values = null;
// create the target array
try {
values = (Streamable[])
Array.newInstance(Class.forName(ctype), size);
} catch (Exception e) {
String errmsg = "Unable to instantiate streamable array " +
"[ctype=" + ctype + "]";
throw new NestableIOException(errmsg, e);
}
// create a list used to map class ids to class names
Object[] cnames = new Object[DEFAULT_SIZE];
// seed our class names with the component type
cnames[0] = ctype;
// read in each of the list elements
for (int ii = 0; ii < size; ii++) {
// read the class id number
short cidx = in.readShort();
// look up the class name
String cname = (cidx > cnames.length - 1) ? null :
(String)cnames[cidx];
if (cname == null) {
// store this class id to class name mapping
cname = in.readUTF();
cnames = ListUtil.add(cnames, cidx, cname);
}
try {
// instantiate the streamable object
Class clazz = Class.forName(cname);
Streamable s = (Streamable)clazz.newInstance();
// read in the object itself
s.readFrom(in);
// and add it to the list
values[ii] = s;
} catch (Exception e) {
String errmsg = "Error instantiating streamable array " +
"element [ctype=" + ctype + ", index=" + ii +
", etype=" + cname + "]";
throw new NestableIOException(errmsg, e);
}
}
return values;
}
/** The default size of the class name lists used when serializing or
* unserializing the list. */
protected static final int DEFAULT_SIZE = 8;
}