org.nustaq.serialization.coders.FSTStreamEncoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fst Show documentation
Show all versions of fst Show documentation
A fast java serialization drop in-replacement and some serialization based utils such as Structs and OffHeap Memory.
/*
* Copyright 2014 Ruediger Moeller.
*
* 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.nustaq.serialization.coders;
import org.nustaq.serialization.*;
import org.nustaq.serialization.util.FSTOutputStream;
import org.nustaq.serialization.util.FSTUtil;
import java.io.IOException;
import java.io.OutputStream;
/**
* Default Coder used for serialization. Serializes into a binary stream
*/
public class FSTStreamEncoder implements FSTEncoder {
private FSTConfiguration conf;
private FSTClazzNameRegistry clnames;
private FSTOutputStream buffout;
private byte[] ascStringCache;
public FSTStreamEncoder(FSTConfiguration conf) {
this.conf = conf;
clnames = (FSTClazzNameRegistry) conf.getCachedObject(FSTClazzNameRegistry.class);
if ( clnames == null ) {
clnames = new FSTClazzNameRegistry(conf.getClassRegistry());
} else {
clnames.clear();
}
}
@Override
public void setConf(FSTConfiguration conf) {
this.conf = conf;
}
void writeFBooleanArr(boolean[] arr, int off, int len) throws IOException {
buffout.ensureFree(len);
for (int i = off; i < off+len; i++) {
buffout.buf[buffout.pos++] = (byte) (arr[i] ? 1 : 0);
}
}
public void writeFFloatArr(float[] arr, int off, int len) throws IOException {
int byteLen = arr.length * 4;
buffout.ensureFree(byteLen);
byte buf[] = buffout.buf;
int count = buffout.pos;
int max = off + len;
for (int i = off; i < max; i++) {
long anInt = Float.floatToIntBits(arr[i]);
buf[count] = (byte) (anInt >>> 0);
buf[count+1] = (byte) (anInt >>> 8);
buf[count+2] = (byte) (anInt >>> 16);
buf[count+3] = (byte) (anInt >>> 24);
count+=4;
}
buffout.pos+= byteLen;
}
public void writeFDoubleArr(double[] arr, int off, int len) throws IOException {
final int byteLen = arr.length * 8;
buffout.ensureFree(byteLen);
final byte buf[] = buffout.buf;
int count = buffout.pos;
final int max = off + len;
for (int i = off; i < max; i++) {
long aLong = Double.doubleToLongBits(arr[i]);
buf[count] = (byte) (aLong >>> 0);
buf[count+1] = (byte) (aLong >>> 8);
buf[count+2] = (byte) (aLong >>> 16);
buf[count+3] = (byte) (aLong >>> 24);
buf[count+4] = (byte) (aLong >>> 32);
buf[count+5] = (byte) (aLong >>> 40);
buf[count+6] = (byte) (aLong >>> 48);
buf[count+7] = (byte) (aLong >>> 56);
count+=8;
}
buffout.pos+= byteLen;
}
// Using ByteBuffers is faster but only with 1.8_u40. seems terrible with prior versions.
// also requires some hacking in order to reuse a bytebuffer
// static Field bbHB, bbCap;
// static {
// Field[] fields = ByteBuffer.class.getDeclaredFields();
// for (int i = 0; i < fields.length; i++) {
// Field fi = fields[i];
// if ( fi.getName() == "hb" ) {
// bbHB = fi;
// bbHB.setAccessible(true);
// }
// }
// fields = Buffer.class.getDeclaredFields();
// for (int i = 0; i < fields.length; i++) {
// Field fi = fields[i];
// if ( fi.getName() == "capacity" ) {
// bbCap = fi;
// bbCap.setAccessible(true);
// }
// }
// }
//
// ThreadLocal buf = new ThreadLocal() {
// @Override
// protected ByteBuffer initialValue() {
// return ByteBuffer.wrap(new byte[0]);
// }
// };
//
// public void writeFDoubleArr(double[] arr, int off, int len) throws IOException {
// int byteLen = arr.length * 8;
// buffout.ensureFree(byteLen);
// int max = off + len;
// ByteBuffer wrap = buf.get();
// try {
// bbHB.set(wrap, buffout.buf);
// bbCap.set(wrap,buffout.buf.length);
// wrap.limit(buffout.pos+byteLen);
// } catch (IllegalAccessException e) {
// e.printStackTrace();
// wrap = ByteBuffer.wrap(buffout.buf, buffout.pos, byteLen).order(ByteOrder.LITTLE_ENDIAN);
// }
// int count = buffout.pos;
// for (int i = off; i < max; i++) {
// long aLong = Double.doubleToLongBits(arr[i]);
// wrap.putLong(count,aLong);
// count += 8;
// }
// buffout.pos+= byteLen;
// }
public void writeFShortArr(short[] arr, int off, int len) throws IOException {
buffout.ensureFree(len*3);
for (int i = off; i < off+len; i++) {
short c = arr[i];
if (c < 255 && c >= 0) {
buffout.buf[buffout.pos++] = (byte) c;
} else {
buffout.buf[buffout.pos] = (byte) 255;
buffout.buf[buffout.pos+1] = (byte) (c >>> 0);
buffout.buf[buffout.pos+2] = (byte) (c >>> 8);
buffout.pos += 3;
}
}
}
public void writeFCharArr(char[] arr, int off, int len) throws IOException {
buffout.ensureFree(len*3);
for (int i = off; i < off+len; i++) {
char c = arr[i];
if (c < 255 && c >= 0) {
buffout.buf[buffout.pos++] = (byte) c;
} else {
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count] = (byte) 255;
buf[count+1] = (byte) (c >>> 0);
buf[count+2] = (byte) (c >>> 8);
buffout.pos += 3;
}
}
}
// uncompressed version
public void writeFIntArr(int[] arr, int off, int len) throws IOException {
int byteLen = arr.length * 4;
buffout.ensureFree(byteLen);
byte buf[] = buffout.buf;
int count = buffout.pos;
int max = off + len;
for (int i = off; i < max; i++) {
long anInt = arr[i];
buf[count] = (byte) (anInt >>> 0);
buf[count+1] = (byte) (anInt >>> 8);
buf[count+2] = (byte) (anInt >>> 16);
buf[count+3] = (byte) (anInt >>> 24);
count+=4;
}
buffout.pos+= byteLen;
}
// compressed version
public void _writeFIntArr(int v[], int off, int len) throws IOException {
final int free = 5 * len;
buffout.ensureFree(free);
final byte[] buf = buffout.buf;
int count = buffout.pos;
for (int i = off; i < off+len; i++) {
final int anInt = v[i];
if ( anInt > -127 && anInt <=127 ) {
buffout.buf[count++] = (byte)anInt;
} else
if ( anInt >= Short.MIN_VALUE && anInt <= Short.MAX_VALUE ) {
buf[count++] = -128;
buf[count++] = (byte) ((anInt >>> 0) & 0xFF);
buf[count++] = (byte) ((anInt >>> 8) & 0xFF);
} else {
buf[count++] = -127;
buf[count++] = (byte) ((anInt >>> 0) & 0xFF);
buf[count++] = (byte) ((anInt >>> 8) & 0xFF);
buf[count++] = (byte) ((anInt >>> 16) & 0xFF);
buf[count++] = (byte) ((anInt >>> 24) & 0xFF);
}
}
buffout.pos = count;
}
void writeFLongArr(long[] arr, int off, int len) throws IOException {
int byteLen = arr.length * 8;
buffout.ensureFree(byteLen);
byte buf[] = buffout.buf;
int count = buffout.pos;
for (int i = off; i < off+len; i++) {
long anInt = arr[i];
buf[count] = (byte) (anInt >>> 0);
buf[count+1] = (byte) (anInt >>> 8);
buf[count+2] = (byte) (anInt >>> 16);
buf[count+3] = (byte) (anInt >>> 24);
buf[count+4] = (byte) (anInt >>> 32);
buf[count+5] = (byte) (anInt >>> 40);
buf[count+6] = (byte) (anInt >>> 48);
buf[count+7] = (byte) (anInt >>> 56);
count += 8;
}
buffout.pos+= byteLen;
}
/**
* write prim array no len no tag
*
*
* @param array
* @throws IOException
*/
public void writePrimitiveArray(Object array, int off, int len) throws IOException {
Class> componentType = array.getClass().getComponentType();
if ( componentType == byte.class ) {
writeRawBytes((byte[]) array, off, len);
} else
if ( componentType == char.class ) {
writeFCharArr((char[]) array, off, len);
} else
if ( componentType == short.class ) {
writeFShortArr((short[]) array, off, len);
} else
if ( componentType == int.class ) {
writeFIntArr((int[]) array, off, len);
} else
if ( componentType == double.class ) {
writeFDoubleArr((double[]) array, off, len);
} else
if ( componentType == float.class ) {
writeFFloatArr((float[]) array, off, len);
} else
if ( componentType == long.class ) {
writeFLongArr((long[]) array, off, len);
} else
if ( componentType == boolean.class ) {
writeFBooleanArr((boolean[]) array, off, len);
} else {
throw new RuntimeException("expected primitive array");
}
}
/**
* does not write length, just plain bytes
*
* @param array
* @param length
* @throws java.io.IOException
*/
public void writeRawBytes(byte[] array, int start, int length) throws IOException {
buffout.ensureFree(length);
System.arraycopy(array, start, buffout.buf, buffout.pos, length);
buffout.pos += length;
}
@Override
public void writeStringUTF(String str) throws IOException {
final int strlen = str.length();
writeFInt(strlen);
buffout.ensureFree(strlen*3);
final byte[] bytearr = buffout.buf;
int count = buffout.pos;
for (int i=0; i= 255) {
bytearr[count-1] = (byte)255;
bytearr[count++] = (byte) ((c >>> 0) & 0xFF);
bytearr[count++] = (byte) ((c >>> 8) & 0xFF);
}
}
buffout.pos = count;
}
/**
* length < 127 !!!!!
*
* @param name
* @throws java.io.IOException
*/
void writeStringAsc(String name) throws IOException {
int len = name.length();
if ( len >= 127 ) {
throw new RuntimeException("Ascii String too long");
}
writeFByte((byte) len);
buffout.ensureFree(len);
if (ascStringCache == null || ascStringCache.length < len)
ascStringCache = new byte[len];
name.getBytes(0, len, ascStringCache, 0);
writeRawBytes(ascStringCache, 0, len);
}
@Override
public void writeFShort(short c) throws IOException {
if (c < 255 && c >= 0) {
writeFByte(c);
} else {
writeFByte(255);
writePlainShort(c);
}
}
public void writeAttributeName(FSTClazzInfo.FSTFieldInfo subInfo) {
}
public boolean writeTag(byte tag, Object info, long somValue, Object toWrite, FSTObjectOutput oout) throws IOException {
writeFByte(tag);
return false;
}
@Override
public void writeFChar(char c) throws IOException {
// -128 = short byte, -127 == 4 byte
if (c < 255 && c >= 0) {
buffout.ensureFree(1);
buffout.buf[buffout.pos++] = (byte) c;
} else {
buffout.ensureFree(3);
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count++] = (byte) 255;
buf[count++] = (byte) (c >>> 0);
buf[count++] = (byte) (c >>> 8);
buffout.pos += 3;
}
}
@Override
public final void writeFByte(int v) throws IOException {
buffout.ensureFree(1);
buffout.buf[buffout.pos++] = (byte) v;
}
@Override
public void writeFInt(int anInt) throws IOException {
// -128 = short byte, -127 == 4 byte
if (anInt > -127 && anInt <= 127) {
if (buffout.buf.length <= buffout.pos + 1) {
buffout.ensureFree(1);
}
buffout.buf[buffout.pos++] = (byte) anInt;
} else if (anInt >= Short.MIN_VALUE && anInt <= Short.MAX_VALUE) {
ensureFree(3);
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count++] = (byte) -128;
buf[count++] = (byte) (anInt >>> 0);
buf[count++] = (byte) (anInt >>> 8);
buffout.pos = count;
} else {
buffout.ensureFree(5);
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count++] = (byte) -127;
buf[count++] = (byte) ((anInt >>> 0) & 0xFF);
buf[count++] = (byte) ((anInt >>> 8) & 0xFF);
buf[count++] = (byte) ((anInt >>> 16) & 0xFF);
buf[count++] = (byte) ((anInt >>> 24) & 0xFF);
buffout.pos = count;
}
}
@Override
public void writeFLong(long anInt) throws IOException {
// -128 = short byte, -127 == 4 byte
if (anInt > -126 && anInt <= 127) {
writeFByte((int) anInt);
} else if (anInt >= Short.MIN_VALUE && anInt <= Short.MAX_VALUE) {
ensureFree(3);
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count++] = (byte) -128;
buf[count++] = (byte) (anInt >>> 0);
buf[count++] = (byte) (anInt >>> 8);
buffout.pos = count;
} else if (anInt >= Integer.MIN_VALUE && anInt <= Integer.MAX_VALUE) {
buffout.ensureFree(5);
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count++] = (byte) -127;
buf[count++] = (byte) ((anInt >>> 0) & 0xFF);
buf[count++] = (byte) ((anInt >>> 8) & 0xFF);
buf[count++] = (byte) ((anInt >>> 16) & 0xFF);
buf[count++] = (byte) ((anInt >>> 24) & 0xFF);
buffout.pos = count;
} else {
buffout.ensureFree(9);
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count++] = (byte) -126;
buf[count++] = (byte) (anInt >>> 0);
buf[count++] = (byte) (anInt >>> 8);
buf[count++] = (byte) (anInt >>> 16);
buf[count++] = (byte) (anInt >>> 24);
buf[count++] = (byte) (anInt >>> 32);
buf[count++] = (byte) (anInt >>> 40);
buf[count++] = (byte) (anInt >>> 48);
buf[count++] = (byte) (anInt >>> 56);
buffout.pos = count;
}
}
/**
* Writes a 4 byte float.
*/
@Override
public void writeFFloat(float value) throws IOException {
writePlainInt(Float.floatToIntBits(value));
}
@Override
public void writeFDouble(double value) throws IOException {
writePlainLong(Double.doubleToLongBits(value));
}
@Override
public int getWritten() {
return buffout.pos-buffout.getOff();
}
/**
* close and flush to underlying stream if present. The stream is also closed
* @throws IOException
*/
@Override
public void close() throws IOException {
buffout.close();
conf.returnObject(clnames);
}
@Override
public void reset(byte[] out) {
if (out==null) {
buffout.reset();
} else {
buffout.reset(out);
}
clnames.clear();
}
@Override
public void skip(int i) {
buffout.pos+=i;
}
/**
* used to write uncompressed int (guaranteed length = 4) at a (eventually recent) position
* @param position
* @param v
*/
@Override
public void writeInt32At(int position, int v) {
buffout.buf[position] = (byte) (v >>> 0);
buffout.buf[position+1] = (byte) (v >>> 8);
buffout.buf[position+2] = (byte) (v >>> 16);
buffout.buf[position+3] = (byte) (v >>> 24);
}
/**
* if output stream is null, just encode into a byte array
* @param outstream
*/
@Override
public void setOutstream(OutputStream outstream) {
if ( buffout == null )
{
// try reuse
buffout = (FSTOutputStream) conf.getCachedObject(FSTOutputStream.class);
if ( buffout == null ) // if fail, alloc
buffout = new FSTOutputStream(1000, outstream);
else
buffout.reset(); // reset resued fstoutput
}
if ( outstream == null )
buffout.setOutstream(buffout);
else
buffout.setOutstream(outstream);
}
/**
* writes current buffer to underlying output and resets buffer.
* @throws IOException
*/
@Override
public void flush() throws IOException {
buffout.flush();
}
@Override
public void ensureFree(int bytes) throws IOException {
buffout.ensureFree(bytes);
}
@Override
public byte[] getBuffer() {
return buffout.buf;
}
public void registerClass(Class possible) {
clnames.registerClass(possible,conf);
}
@Override
public final void writeClass(Class cl) {
try {
clnames.encodeClass(this,cl);
} catch ( IOException e) {
FSTUtil.rethrow(e);
}
}
@Override
public final void writeClass(FSTClazzInfo clInf) {
try {
clnames.encodeClass(this, clInf);
} catch ( IOException e) {
FSTUtil.rethrow(e);
}
}
private void writePlainLong(long v) throws IOException {
buffout.ensureFree(8);
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count++] = (byte) (v >>> 0);
buf[count++] = (byte) (v >>> 8);
buf[count++] = (byte) (v >>> 16);
buf[count++] = (byte) (v >>> 24);
buf[count++] = (byte) (v >>> 32);
buf[count++] = (byte) (v >>> 40);
buf[count++] = (byte) (v >>> 48);
buf[count++] = (byte) (v >>> 56);
buffout.pos += 8;
}
private void writePlainShort(int v) throws IOException {
buffout.ensureFree(2);
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count++] = (byte) (v >>> 0);
buf[count++] = (byte) (v >>> 8);
buffout.pos += 2;
}
private void writePlainChar(int v) throws IOException {
buffout.ensureFree(2);
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count++] = (byte) (v >>> 0);
buf[count++] = (byte) (v >>> 8);
buffout.pos += 2;
}
private void writePlainInt(int v) throws IOException {
buffout.ensureFree(4);
byte[] buf = buffout.buf;
int count = buffout.pos;
buf[count++] = (byte) ((v >>> 0) & 0xFF);
buf[count++] = (byte) ((v >>> 8) & 0xFF);
buf[count++] = (byte) ((v >>> 16) & 0xFF);
buf[count++] = (byte) ((v >>> 24) & 0xFF);
buffout.pos = count;
}
public void externalEnd(FSTClazzInfo clz) {
}
@Override
public boolean isWritingAttributes() {
return false;
}
public boolean isPrimitiveArray(Object array, Class> componentType) {
return componentType.isPrimitive();
}
public boolean isTagMultiDimSubArrays() {
return false;
}
@Override
public void writeVersionTag(int version) throws IOException {
writeFByte(version);
}
@Override
public boolean isByteArrayBased() {
return true;
}
@Override
public void writeArrayEnd() {
}
@Override
public void writeFieldsEnd(FSTClazzInfo serializationInfo) {
}
@Override
public FSTConfiguration getConf() {
return conf;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy