package org.mapdb.volume;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.mapdb.DBException;
import org.mapdb.DataIO;
import org.mapdb.DataInput2;
import java.io.File;
import java.nio.ByteBuffer;
/**
* Volume backed by on-heap byte[] with maximal fixed size 2GB.
* For thread-safety it can not be grown
*/
public final class SingleByteArrayVol extends Volume {
protected final static VolumeFactory FACTORY = new VolumeFactory() {
@Override
public Volume makeVolume(String file, boolean readOnly, long fileLockWait, int sliceShift, long initSize, boolean fixedSize) {
if(initSize>Integer.MAX_VALUE)
throw new IllegalArgumentException("startSize larger 2GB");
return new org.mapdb.volume.SingleByteArrayVol((int) initSize);
}
@NotNull
@Override
public boolean exists(@Nullable String file) {
return false;
}
@Override
public boolean handlesReadonly() {
return false;
}
};
protected final byte[] data;
public SingleByteArrayVol(int size) {
this(new byte[size]);
}
public SingleByteArrayVol(byte[] data){
this.data = data;
}
@Override
public void ensureAvailable(long offset) {
if(offset > data.length){
throw new DBException.VolumeMaxSizeExceeded(data.length, offset);
}
}
@Override
public void truncate(long size) {
//unsupported
//TODO throw an exception?
}
@Override
public void putLong(long offset, long v) {
DataIO.putLong(data, (int) offset, v);
}
@Override
public void putInt(long offset, int value) {
int pos = (int) offset;
data[pos++] = (byte) (0xff & (value >> 24));
data[pos++] = (byte) (0xff & (value >> 16));
data[pos++] = (byte) (0xff & (value >> 8));
data[pos++] = (byte) (0xff & (value));
}
@Override
public void putByte(long offset, byte value) {
data[(int) offset] = value;
}
@Override
public void putData(long offset, byte[] src, int srcPos, int srcSize) {
System.arraycopy(src, srcPos, data, (int) offset, srcSize);
}
@Override
public void putData(long offset, ByteBuffer buf) {
buf.get(data, (int) offset, buf.remaining());
}
@Override
public void copyTo(long inputOffset, Volume target, long targetOffset, long size) {
//TODO size>Integer.MAX_VALUE
target.putData(targetOffset,data, (int) inputOffset, (int) size);
}
@Override
public void clear(long startOffset, long endOffset) {
int start = (int) startOffset;
int end = (int) endOffset;
int pos = start;
while(pos<end){
System.arraycopy(CLEAR,0,data,pos, Math.min(CLEAR.length, end-pos));
pos+=CLEAR.length;
}
}
@Override
public long getLong(long offset) {
return DataIO.getLong(data, (int) offset);
}
@Override
public int getInt(long offset) {
int pos = (int) offset;
//TODO verify loop
final int end = pos + 4;
int ret = 0;
for (; pos < end; pos++) {
ret = (ret << 8) | (data[pos] & 0xFF);
}
return ret;
}
@Override
public byte getByte(long offset) {
return data[((int) offset)];
}
@Override
public DataInput2 getDataInput(long offset, int size) {
return new DataInput2.ByteArray(data, (int) offset);
}
@Override
public void getData(long offset, byte[] bytes, int bytesPos, int length) {
System.arraycopy(data, (int) offset,bytes,bytesPos,length);
}
@Override
public void close() {
if (!closed.compareAndSet(false,true))
return;
//TODO perhaps set `data` to null? what are performance implications for non-final fieldd?
}
@Override
public void sync() {
}
@Override
public int sliceSize() {
return -1;
}
@Override
public boolean isSliced() {
return false;
}
@Override
public long length() {
return data.length;
}
@Override
public boolean isReadOnly() {
return false;
}
@Override
public File getFile() {
return null;
}
@Override
public boolean getFileLocked() {
return false;
}
}