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