All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nustaq.serialization.coders.FSTBytezEncoder Maven / Gradle / Ivy

Go to download

A fast java serialization drop in-replacement and some serialization based utils such as Structs and OffHeap Memory.

There is a newer version: 3.0.4-jdk17
Show newest version
/*
 * 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.offheap.bytez.BasicBytez;
import org.nustaq.offheap.bytez.onheap.HeapBytez;
import org.nustaq.serialization.*;
import org.nustaq.serialization.simpleapi.FSTBufferTooSmallException;
import org.nustaq.serialization.util.FSTUtil;

import java.io.IOException;
import java.io.OutputStream;

/**
 * Created by ruedi on 08.11.2014.
 *
 * Enables serialization to arbitrary byte oriented memory
 *
 * no compression is applied, so writeFxx == writePlainXX
 */
public class FSTBytezEncoder implements FSTEncoder {

    private FSTConfiguration conf;

    private FSTClazzNameRegistry clnames;
    private BasicBytez buffout;
    private long pos;
    private byte[] ascStringCache;
    OutputStream outStream;
    boolean autoResize = true;

    public FSTBytezEncoder(FSTConfiguration conf, BasicBytez base) {
        if ( FSTConfiguration.isAndroid )
            throw new RuntimeException("not supported on android");
        this.conf = conf;
        buffout = base;
        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 {
        ensureFree(len);
        buffout.setBoolean(pos,arr,off,len);
        pos += len;
    }

    public void writeFFloatArr(float[] arr, int off, int len) throws IOException {
        ensureFree(4*len);
        buffout.setFloat(pos, arr, off, len);
        pos += 4*len;
    }

    public void writeFDoubleArr(double[] arr, int off, int len) throws IOException {
        ensureFree(8*len);
        buffout.setDouble(pos,arr,off,len);
        pos += 8 * len;
    }

    public void writeFShortArr(short[] arr, int off, int len) throws IOException {
        ensureFree(2*len);
        buffout.setShort(pos, arr, off, len);
        pos += 2 * len;
    }

    public void writeFCharArr(char[] arr, int off, int len) throws IOException {
        ensureFree(2*len);
        buffout.setChar(pos,arr,off,len);
        pos += 2 * len;
    }

    void writeFIntArr(int[] arr, int off, int len) throws IOException {
        ensureFree(4*len);
        buffout.setInt(pos, arr, off, len);
        pos += 4 * len;
    }

    void writeFLongArr(long[] arr, int off, int len) throws IOException {
        ensureFree(8*len);
        buffout.setLong(pos, arr, off, len);
        pos += 8 * len;
    }

    /**
     * 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 {
        ensureFree((int) (pos+length));
        buffout.set(pos,array,start,length);
        pos += length;
    }

    char chBufS[];
    char[] getCharBuf(int siz) {
        char chars[] = chBufS;
        if (chars == null || chars.length < siz) {
            chars = new char[Math.max(siz, 15)];
            chBufS = chars;
        }
        return chars;
    }

    @Override
    public void writeStringUTF(String str) throws IOException {
        final int strlen = str.length();
        writeFInt(strlen);
        ensureFree(strlen*2);
        char c[] = getCharBuf(strlen);
        str.getChars(0,strlen,c,0);
        buffout.setChar(pos,c,0,strlen);
        pos += strlen*2;
    }

    @Override
    public void writeFShort(short c) throws IOException {
        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 {
        writePlainChar(c);
    }

    @Override
    public final void writeFByte(int v) throws IOException {
        ensureFree(1);
        buffout.put(pos++, (byte) v);
    }

    @Override
    public void writeFInt(int anInt) throws IOException {
        writePlainInt(anInt);
    }

    @Override
    public void writeFLong(long anInt) throws IOException {
        writePlainLong(anInt);
    }

    /**
     * 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 (int) pos;
    }

    /**
     * close and flush to underlying stream if present. The stream is also closed
     * @throws IOException
     */
    @Override
    public void close() throws IOException {
        conf.returnObject(clnames);
    }

    @Override
    public void reset(byte[] out) {
        pos = 0;
        clnames.clear();
        if (out!=null)
            throw new RuntimeException("not implemented");
    }

    @Override
    public void skip(int i) {
        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) {
        try {
            ensureFree( position+4);
        } catch (IOException e) {
            FSTUtil.rethrow(e);
        }
        buffout.putInt(position,v);
    }

    /**
     * if output stream is null, just encode into a byte array
     * @param outstream
     */
    @Override
    public void setOutstream(OutputStream outstream) {
        this.outStream = outstream;
    }

    /**
     * writes current buffer to underlying output and resets buffer.
     * @throws IOException
     */
    @Override
    public void flush() throws IOException {
        if ( outStream != null )
            outStream.write(getBuffer(), 0, (int) pos);
        pos = 0;
    }

    @Override
    public void ensureFree(int bytes) throws IOException {
        if ( buffout.length() <= pos+bytes) {
            if ( autoResize ) {
                BasicBytez newbytez = buffout.newInstance(Math.max(pos + bytes, Math.min(Integer.MAX_VALUE-10, buffout.length() * 2)));
                buffout.copyTo(newbytez, 0, 0, pos);
                // debug
                //            for ( int i = 0; i < pos; i++) {
                //                if ( buffout.get(i) != newbytez.get(i) ) {
                //                    throw new RuntimeException("error");
                //                }
                //            }
                buffout = newbytez;
            } else {
                throw FSTBufferTooSmallException.Instance;
            }
        }
    }

    // default is true
    public boolean isAutoResize() {
        return autoResize;
    }

    public void setAutoResize(boolean autoResize) {
        this.autoResize = autoResize;
    }

    @Override
    public byte[] getBuffer() {
        if (isPlainBAAccessible()) {
            return ((HeapBytez) buffout).asByteArray();
        }
        byte res[] = new byte[(int) pos];
        buffout.getArr(0,res,0, (int) pos);
        return res;
    }

    protected boolean isPlainBAAccessible() {
        return buffout.getClass() == HeapBytez.class && ((HeapBytez) buffout).getOffsetIndex() == 0;
    }

    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 {
        ensureFree(8);
        buffout.putLong(pos,v);
        pos += 8;
    }

    private void writePlainShort(int v) throws IOException {
        ensureFree(2);
        buffout.putShort(pos, (short) v);
        pos += 2;
    }

    private void writePlainChar(int v) throws IOException {
        ensureFree(2);
        buffout.putChar(pos, (char) v);
        pos += 2;
    }

    private void writePlainInt(int v) throws IOException {
        ensureFree(4);
        buffout.putInt(pos, v);
        pos += 4;
    }

    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 false || isPlainBAAccessible();
    }

    @Override
    public void writeArrayEnd() {

    }

    @Override
    public void writeFieldsEnd(FSTClazzInfo serializationInfo) {

    }

    @Override
    public FSTConfiguration getConf() {
        return conf;
    }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy