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

io.activej.serializer.stream.StreamInput Maven / Gradle / Ivy

Go to download

Extremely fast and space-efficient serializers. Implemented using bytecode engineering.

There is a newer version: 6.0-rc2
Show newest version
package io.activej.serializer.stream;

import io.activej.serializer.BinaryInput;
import io.activej.serializer.CorruptedDataException;
import org.jetbrains.annotations.Nullable;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;

import static java.lang.Math.max;
import static java.nio.charset.StandardCharsets.UTF_8;

public class StreamInput implements Closeable {
	public static final int DEFAULT_BUFFER_SIZE = 16384;

	private BinaryInput in;
	private int limit;
	private final InputStream inputStream;

	private char[] charArray = new char[128];

	private StreamInput(InputStream inputStream, BinaryInput binaryInput) {
		this.inputStream = inputStream;
		this.in = binaryInput;
		this.limit = binaryInput.array.length;
	}

	private StreamInput(InputStream inputStream, int initialBufferSize) {
		this.inputStream = inputStream;
		this.in = new BinaryInput(allocate(initialBufferSize));
	}

	public static StreamInput create(InputStream inputStream) {
		return new StreamInput(inputStream, DEFAULT_BUFFER_SIZE);
	}

	public static StreamInput create(InputStream inputStream, int bufferSize) {
		return new StreamInput(inputStream, bufferSize);
	}

	public static StreamInput create(BinaryInput binaryInput) {
		return new StreamInput(InputStream.nullInputStream(), binaryInput);
	}

	public static StreamInput create(InputStream inputStream, BinaryInput binaryInput) {
		return new StreamInput(inputStream, binaryInput);
	}

	@Override
	public final void close() throws IOException {
		if (in != null) {
			recycle(in.array());
			in = null;
		}
		inputStream.close();
	}

	protected byte[] allocate(int size) {
		return new byte[size];
	}

	protected void recycle(byte[] array) {
	}

	public BinaryInput in() {
		return in;
	}

	public void in(BinaryInput in) {
		this.in = in;
	}

	public int limit() {
		return limit;
	}

	public int remaining() {
		return limit - in.pos();
	}

	public void ensure(int bytes) throws IOException {
		if (remaining() < bytes) {
			doEnsureRead(bytes);
		}
	}

	private void doEnsureRead(int size) throws IOException {
		while (remaining() < size) {
			ensureWriteRemaining(size);
			int bytesRead = inputStream.read(in.array(), limit, in.array().length - limit);
			if (bytesRead == -1) {
				close();
				throw new EOSException();
			}
			limit += bytesRead;
		}
	}

	private void ensureWriteRemaining(int size) {
		int writeRemaining = in.array().length - limit;
		if (writeRemaining < size) {
			int readRemaining = remaining();
			if (in.array.length - readRemaining >= size) {
				System.arraycopy(in.array(), in.pos(), in.array(), 0, readRemaining);
				limit = readRemaining;
				in.pos = 0;
			} else {
				byte[] bytes = allocate(max(in.array.length, size));
				System.arraycopy(in.array(), in.pos(), bytes, 0, readRemaining);
				limit -= in.pos();
				recycle(in.array);
				in = new BinaryInput(bytes);
			}
		}
	}

	public final boolean isEndOfStream() throws IOException {
		if (remaining() != 0) return false;

		ensureWriteRemaining(1);
		int bytesRead = inputStream.read(in.array(), in.pos, 1);
		if (bytesRead == -1) {
			return true;
		}
		limit += bytesRead;
		return false;
	}

	private char[] ensureCharArray(int length) {
		if (charArray.length < length) {
			charArray = new char[length + (length >>> 2)];
		}
		return charArray;
	}

	public final int read(byte[] b) throws IOException {
		return read(b, 0, b.length);
	}

	public final int read(byte[] b, int off, int len) throws IOException {
		if (in.pos < limit) {
			int copy = Math.min(limit - in.pos, len);
			in.read(b, off, copy);
			off += copy;
			len -= copy;
		}
		readBytes(b, off, len);
		return len;
	}

	private void readBytes(byte[] b, int off, int len) throws IOException {
		while (len > 0) {
			int bytesRead = inputStream.read(b, off, len);
			if (bytesRead == -1) {
				close();
				throw new EOSException();
			}
			off += bytesRead;
			len -= bytesRead;
		}
	}

	public final byte readByte() throws IOException {
		return in.pos < limit ? in.readByte() : readByteImpl();
	}

	private byte readByteImpl() throws IOException {
		doEnsureRead(1);
		return in.readByte();
	}

	public final boolean readBoolean() throws IOException {
		ensure(1);
		return in.readBoolean();
	}

	public final short readShort() throws IOException {
		ensure(2);
		return in.readShort();
	}

	public final int readInt() throws IOException {
		ensure(4);
		return in.readInt();
	}

	public final long readLong() throws IOException {
		ensure(8);
		return in.readLong();
	}

	public final int readVarInt() throws IOException {
		int result;
		byte b = readByte();
		if (b >= 0) {
			result = b;
		} else {
			result = b & 0x7f;
			if ((b = readByte()) >= 0) {
				result |= b << 7;
			} else {
				result |= (b & 0x7f) << 7;
				if ((b = readByte()) >= 0) {
					result |= b << 14;
				} else {
					result |= (b & 0x7f) << 14;
					if ((b = readByte()) >= 0) {
						result |= b << 21;
					} else {
						result |= (b & 0x7f) << 21;
						if ((b = readByte()) >= 0) {
							result |= b << 28;
						} else {
							close();
							throw new CorruptedDataException("VarInt value takes more than 5 bytes");
						}
					}
				}
			}
		}
		return result;
	}

	public final long readVarLong() throws IOException {
		long result = 0;
		for (int offset = 0; offset < 64; offset += 7) {
			byte b = readByte();
			result |= (long) (b & 0x7F) << offset;
			if ((b & 0x80) == 0)
				return result;
		}
		close();
		throw new CorruptedDataException("VarLong value takes more than 10 bytes");
	}

	public final float readFloat() throws IOException {
		ensure(4);
		return in.readFloat();
	}

	public final double readDouble() throws IOException {
		ensure(8);
		return in.readDouble();
	}

	public final char readChar() throws IOException {
		ensure(2);
		return in.readChar();
	}

	public final String readString() throws IOException {
		return readUTF8();
	}

	public final String readUTF8() throws IOException {
		int length = readVarInt();
		if (length == 0) return "";
		ensure(length);
		String str = new String(in.array(), in.pos(), length, UTF_8);
		in.pos(in.pos() + length);
		return str;
	}

	public final String readIso88591() throws IOException {
		int length = readVarInt();
		if (length == 0) return "";
		ensure(length);

		char[] chars = ensureCharArray(length);
		for (int i = 0; i < length; i++) {
			int c = readByte() & 0xff;
			chars[i] = (char) c;
		}
		return new String(chars, 0, length);
	}

	public final String readUTF16() throws IOException {
		int length = readVarInt();
		if (length == 0) return "";
		ensure(length * 2);

		char[] chars = ensureCharArray(length);
		for (int i = 0; i < length; i++) {
			byte b1 = in.array()[in.pos];
			byte b2 = in.array()[in.pos + 1];
			in.pos += 2;
			chars[i] = (char) (((b1 & 0xFF) << 8) + (b2 & 0xFF));
		}
		return new String(chars, 0, length);
	}

	public final @Nullable String readUTF8Nullable() throws IOException {
		int length = readVarInt();
		if (length-- == 0) return null;
		if (length == 0) return "";
		ensure(length);
		String str = new String(in.array(), in.pos(), length, UTF_8);
		in.pos(in.pos() + length);
		return str;
	}

	public final @Nullable String readIso88591Nullable() throws IOException {
		int length = readVarInt();
		if (length-- == 0) return null;
		if (length == 0) return "";
		ensure(length);

		char[] chars = ensureCharArray(length);
		for (int i = 0; i < length; i++) {
			int c = readByte() & 0xff;
			chars[i] = (char) c;
		}
		return new String(chars, 0, length);
	}

	public final @Nullable String readUTF16Nullable() throws IOException {
		int length = readVarInt();
		if (length-- == 0) return null;
		if (length == 0) return "";
		ensure(length * 2);

		char[] chars = ensureCharArray(length);
		for (int i = 0; i < length; i++) {
			byte b1 = in.array()[in.pos];
			byte b2 = in.array()[in.pos + 1];
			in.pos += 2;
			chars[i] = (char) (((b1 & 0xFF) << 8) + (b2 & 0xFF));
		}
		return new String(chars, 0, length);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy