package org.mapdb.serializer;
import org.jetbrains.annotations.NotNull;
import org.mapdb.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
/**
* Serializer for tuples. It serializes fixed size array, where each array index can use different serializer.
* <p/>
* It takes array of serializes in constructor parameter. All tuples (arrays) must have the same size.
*/
public class SerializerArrayTuple implements GroupSerializer<Object[]>, DB.DBAware {
protected final Serializer[] ser;
protected final Comparator[] comp;
protected final int size;
public SerializerArrayTuple(int size) {
this.size = size;
ser = new Serializer[size];
comp = new Comparator[size];
}
public SerializerArrayTuple(Serializer[] serializers, Comparator[] comparators) {
this.ser = serializers.clone();
this.comp = comparators.clone();
this.size = ser.length;
}
public SerializerArrayTuple(Serializer... serializers) {
this.ser = serializers.clone();
this.comp = ser;
this.size = ser.length;
}
protected Object[] cast(Object o){
if(CC.ASSERT && ((Object[])o).length%size!=0) {
throw new AssertionError();
}
return (Object[])o;
}
@Override
public void serialize(@NotNull DataOutput2 out, @NotNull Object[] value) throws IOException {
for(int i=0;i<size;i++){
ser[i].serialize(out, value[i]);
}
}
@Override
public Object[] deserialize(@NotNull DataInput2 input, int available) throws IOException {
Object[] v = new Object[size];
for(int i=0;i<size;i++){
v[i] = ser[i].deserialize(input,-1);
}
return v;
}
@Override
public void valueArraySerialize(DataOutput2 out, Object vals) throws IOException {
//TODO delta compression
Object[] v = cast(vals);
for(int i=0;i<v.length;i++){
ser[i%size].serialize(out,v[i]);
}
}
@Override
public Object valueArrayDeserialize(DataInput2 in, int size) throws IOException {
Object[] v = new Object[size * this.size];
for (int i = 0; i < v.length; i++) {
v[i] = ser[i%this.size].deserialize(in,-1);
}
return v;
}
@Override
public int valueArraySearch(Object keys, Object[] key) {
return Arrays.binarySearch(valueArrayToArray(keys), key, (Serializer)this);
}
@Override
public int valueArraySearch(Object keys, Object[] key, Comparator comparator) {
return Arrays.binarySearch(valueArrayToArray(keys), key, comparator);
}
@Override
public Object[] valueArrayGet(Object vals, int pos) {
pos*=size;
return Arrays.copyOfRange(cast(vals), pos, pos+size);
}
@Override
public int valueArraySize(Object vals) {
return cast(vals).length/size;
}
@Override
public Object valueArrayEmpty() {
return new Object[0];
}
@Override
public Object valueArrayPut(Object vals, int pos, Object[] newValue) {
if(CC.ASSERT && newValue.length%size!=0)
throw new AssertionError();
Object[] array = cast(vals);
pos*=size;
final Object[] ret = Arrays.copyOf(array, array.length+size);
if(pos<array.length){
System.arraycopy(array, pos, ret, pos+size, array.length-pos);
}
System.arraycopy(newValue,0,ret,pos,size);
return ret;
}
@Override
public Object valueArrayUpdateVal(Object vals, int pos, Object[] newValue) {
if(CC.ASSERT && newValue.length!=size)
throw new AssertionError();
Object[] ret = cast(vals).clone();
System.arraycopy(newValue, 0, ret, pos*size, size);
return ret;
}
@Override
public Object valueArrayFromArray(Object[] objects) {
Object[] v = new Object[objects.length*size];
int pos = 0;
for(Object oo:objects){
Object[] oo2= (Object[]) oo;
if(CC.ASSERT && oo2.length!=size)
throw new AssertionError();
for(Object o:oo2)
v[pos++]=o;
}
return v;
}
@Override
public Object valueArrayCopyOfRange(Object vals, int from, int to) {
return Arrays.copyOfRange(cast(vals), from*size, to*size);
}
@Override
public Object valueArrayDeleteValue(Object vals0, int pos) {
pos*=size;
Object[] vals = cast(vals0);
Object[] vals2 = new Object[vals.length-size];
System.arraycopy(vals, 0, vals2, 0, pos-size);
System.arraycopy(vals, pos, vals2, pos-size, vals2.length-(pos-size));
return vals2;
}
@Override
public Object[] nextValue(Object[] value) {
return Arrays.copyOf(value, value.length+1); //it expands array by one, and insert null at last position.
}
@Override
public boolean equals(Object[] a1, Object[] a2) {
if(a1.length!=a2.length)
return false;
for(int i=0;i<a1.length;i++){
if(!ser[i%size].equals(a1[i],a2[i]))
return false;
}
return true;
}
@Override
public int compare(Object[] o1, Object[] o2) {
int len = Math.min(o1.length, o2.length);
for(int i=0;i<len;i++){
Object a1 = o1[i];
Object a2 = o2[i];
if(a1==a2)
continue;
if(a1==null)
return 1;
if(a2==null)
return -1;
int res = comp[i].compare(a1, a2);
if(res!=0)
return res;
}
return Integer.compare(o1.length,o2.length);
}
@Override
public int hashCode(@NotNull Object[] objects, int seed) {
if(CC.ASSERT && objects.length%size!=0)
throw new AssertionError();
for(int i=0;i<objects.length;i++){
seed+= DataIO.intHash(ser[i].hashCode(objects[i],seed));
}
return seed;
}
@Override
public boolean isTrusted() {
for(Serializer s:ser)
if(!s.isTrusted())
return false;
return true;
}
@Override
public void callbackDB(@NotNull DB db) {
for(int i=0; i<size; i++){
if(ser[i]==null)
ser[i] = db.getDefaultSerializer();
if(comp[i]==null)
comp[i] = db.getDefaultSerializer();
}
}
}