package org.mapdb;
import java.io.DataOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
/**
* Output of serialization
*/
public class DataOutput2 extends OutputStream implements DataOutput{
public byte[] buf;
public int pos;
public int sizeMask;
public DataOutput2(){
pos = 0;
buf = new byte[128]; //PERF take hint from serializer for initial size
sizeMask = 0xFFFFFFFF-(buf.length-1);
}
public byte[] copyBytes(){
return Arrays.copyOf(buf, pos);
}
/**
* make sure there will be enough space in buffer to write N bytes
* @param n number of bytes which can be safely written after this method returns
*/
public void ensureAvail(int n) {
//$DELAY$
n+=pos;
if ((n&sizeMask)!=0) {
grow(n);
}
}
private void grow(int n) {
//$DELAY$
int newSize = Math.max(DataIO.nextPowTwo(n),buf.length);
sizeMask = 0xFFFFFFFF-(newSize-1);
buf = Arrays.copyOf(buf, newSize);
}
@Override
public void write(final int b) throws IOException {
ensureAvail(1);
//$DELAY$
buf[pos++] = (byte) b;
}
@Override
public void write(byte[] b) throws IOException {
write(b,0,b.length);
}
@Override
public void write(final byte[] b, final int off, final int len) throws IOException {
ensureAvail(len);
//$DELAY$
System.arraycopy(b, off, buf, pos, len);
pos += len;
}
@Override
public void writeBoolean(final boolean v) throws IOException {
ensureAvail(1);
//$DELAY$
buf[pos++] = (byte) (v ? 1 : 0);
}
@Override
public void writeByte(final int v) throws IOException {
ensureAvail(1);
//$DELAY$
buf[pos++] = (byte) (v);
}
@Override
public void writeShort(final int v) throws IOException {
ensureAvail(2);
//$DELAY$
buf[pos++] = (byte) (0xff & (v >> 8));
//$DELAY$
buf[pos++] = (byte) (0xff & (v));
}
@Override
public void writeChar(final int v) throws IOException {
ensureAvail(2);
buf[pos++] = (byte) (v>>>8);
buf[pos++] = (byte) (v);
}
@Override
public void writeInt(final int v) throws IOException {
ensureAvail(4);
buf[pos++] = (byte) (0xff & (v >> 24));
//$DELAY$
buf[pos++] = (byte) (0xff & (v >> 16));
buf[pos++] = (byte) (0xff & (v >> 8));
//$DELAY$
buf[pos++] = (byte) (0xff & (v));
}
@Override
public void writeLong(final long v) throws IOException {
ensureAvail(8);
buf[pos++] = (byte) (0xff & (v >> 56));
buf[pos++] = (byte) (0xff & (v >> 48));
//$DELAY$
buf[pos++] = (byte) (0xff & (v >> 40));
buf[pos++] = (byte) (0xff & (v >> 32));
buf[pos++] = (byte) (0xff & (v >> 24));
//$DELAY$
buf[pos++] = (byte) (0xff & (v >> 16));
buf[pos++] = (byte) (0xff & (v >> 8));
buf[pos++] = (byte) (0xff & (v));
//$DELAY$
}
@Override
public void writeFloat(final float v) throws IOException {
writeInt(Float.floatToIntBits(v));
}
@Override
public void writeDouble(final double v) throws IOException {
writeLong(Double.doubleToLongBits(v));
}
@Override
public void writeBytes(final String s) throws IOException {
writeUTF(s);
}
@Override
public void writeChars(final String s) throws IOException {
writeUTF(s);
}
@Override
public void writeUTF(final String s) throws IOException {
final int len = s.length();
packInt(len);
for (int i = 0; i < len; i++) {
//$DELAY$
int c = (int) s.charAt(i);
packInt(c);
}
}
public void packInt(int value) throws IOException {
ensureAvail(5); //ensure worst case bytes
// Optimize for the common case where value is small. This is particular important where our caller
// is SerializerBase.SER_STRING.serialize because most chars will be ASCII characters and hence in this range.
// credit Max Bolingbroke https://github.com/jankotek/MapDB/pull/489
int shift = (value & ~0x7F); //reuse variable
if (shift != 0) {
shift = 31 - Integer.numberOfLeadingZeros(value);
shift -= shift % 7; // round down to nearest multiple of 7
while (shift != 0) {
buf[pos++] = (byte) ((value >>> shift) & 0x7F);
shift -= 7;
}
}
buf[pos++] = (byte) ((value & 0x7F)| 0x80);
}
public void packIntBigger(int value) throws IOException {
ensureAvail(5); //ensure worst case bytes
int shift = 31-Integer.numberOfLeadingZeros(value);
shift -= shift%7; // round down to nearest multiple of 7
while(shift!=0){
buf[pos++] = (byte) ((value>>>shift) & 0x7F);
shift-=7;
}
buf[pos++] = (byte) ((value & 0x7F)|0x80);
}
public void packLong(long value) {
ensureAvail(10); //ensure worst case bytes
int shift = 63-Long.numberOfLeadingZeros(value);
shift -= shift%7; // round down to nearest multiple of 7
while(shift!=0){
buf[pos++] = (byte) ((value>>>shift) & 0x7F);
shift-=7;
}
buf[pos++] = (byte) ((value & 0x7F) | 0x80);
}
public void packLongArray(long[] array, int fromIndex, int toIndex ) {
for(int i=fromIndex;i<toIndex;i++){
long value = array[i];
ensureAvail(10); //ensure worst case bytes
int shift = 63-Long.numberOfLeadingZeros(value);
shift -= shift%7; // round down to nearest multiple of 7
while(shift!=0){
buf[pos++] = (byte) ((value>>>shift) & 0x7F);
shift-=7;
}
buf[pos++] = (byte) ((value & 0x7F) | 0x80);
}
}
}