仍然和 fury 有明显的性能差距,从数组的数据写入的角度尝试优化
parent
81f0e22d76
commit
1714fbd246
38
pom.xml
38
pom.xml
|
@ -2,7 +2,7 @@
|
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<groupId>com.jfirer</groupId>
|
||||
<artifactId>JfireSE</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
@ -13,7 +13,18 @@
|
|||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>nexus3</id>
|
||||
<name>nexus</name>
|
||||
<url>http://yynas.cn:8081/repository/maven-releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>nexus3</id>
|
||||
<name>nexus</name>
|
||||
<url>http://yynas.cn:8081/repository/maven-snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
@ -32,6 +43,29 @@
|
|||
<version>1.18.30</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jfirer</groupId>
|
||||
<artifactId>Fse</artifactId>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.furyio</groupId>
|
||||
<artifactId>fury-core</artifactId>
|
||||
<version>0.4.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
<version>1.37</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>1.37</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
|
|
@ -13,7 +13,8 @@ public class ClassInfo
|
|||
private String className;
|
||||
private Serializer serializer;
|
||||
private JfireSE jfireSE;
|
||||
private Object[] refTracking;
|
||||
private Object[] tracking;
|
||||
private boolean refTracking;
|
||||
private int refTrackingIndex = 0;
|
||||
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance, boolean knownClazz)
|
||||
|
@ -29,7 +30,7 @@ public class ClassInfo
|
|||
}
|
||||
if (knownClazz)
|
||||
{
|
||||
if (jfireSE.isCycleSupport())
|
||||
if (refTracking)
|
||||
{
|
||||
int tracking = addTracking(instance);
|
||||
if (tracking == -1)
|
||||
|
@ -53,7 +54,7 @@ public class ClassInfo
|
|||
}
|
||||
else
|
||||
{
|
||||
if (jfireSE.isCycleSupport())
|
||||
if (refTracking)
|
||||
{
|
||||
if (classId == ClassInfoResolver.NO_CLASS_ID)
|
||||
{
|
||||
|
@ -101,32 +102,65 @@ public class ClassInfo
|
|||
}
|
||||
}
|
||||
|
||||
public void reset()
|
||||
public void reset(int tempClassIdStart)
|
||||
{
|
||||
classId = ClassInfoResolver.NO_CLASS_ID;
|
||||
if (classId < tempClassIdStart)
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
classId = ClassInfoResolver.NO_CLASS_ID;
|
||||
}
|
||||
refTrackingIndex = 0;
|
||||
}
|
||||
|
||||
public int addTracking(Object instance)
|
||||
{
|
||||
if (refTracking == null)
|
||||
if (tracking == null)
|
||||
{
|
||||
refTracking = new Object[4];
|
||||
tracking = new Object[4];
|
||||
}
|
||||
for (int i = 0; i < refTrackingIndex; i++)
|
||||
{
|
||||
if (refTracking[i] == instance)
|
||||
if (tracking[i] == instance)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if (refTrackingIndex == refTracking.length)
|
||||
if (refTrackingIndex == tracking.length)
|
||||
{
|
||||
Object[] newRefTracking = new Object[refTracking.length * 2];
|
||||
System.arraycopy(refTracking, 0, newRefTracking, 0, refTracking.length);
|
||||
refTracking = newRefTracking;
|
||||
Object[] newRefTracking = new Object[tracking.length * 2];
|
||||
System.arraycopy(tracking, 0, newRefTracking, 0, tracking.length);
|
||||
tracking = newRefTracking;
|
||||
}
|
||||
refTracking[refTrackingIndex++] = instance;
|
||||
tracking[refTrackingIndex++] = instance;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析的是序列化协议中序号 3 的内容
|
||||
*
|
||||
* @param byteArray
|
||||
* @param refTracking
|
||||
* @return
|
||||
*/
|
||||
public Object readBytes(InternalByteArray byteArray, boolean refTracking)
|
||||
{
|
||||
if (serializer == null)
|
||||
{
|
||||
serializer = jfireSE.getSerializer(clazz);
|
||||
}
|
||||
Object instance = serializer.readBytes(byteArray);
|
||||
if (refTracking)
|
||||
{
|
||||
addTracking(instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Object getTracking(int instanceId)
|
||||
{
|
||||
return tracking[instanceId];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,46 +1,59 @@
|
|||
package com.jfirer.se;
|
||||
|
||||
import com.jfirer.se.serializer.SerializerResolver;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ClassInfoResolver
|
||||
{
|
||||
public static int NO_CLASS_ID = 0;
|
||||
private Map<Class, ClassInfo> store = new IdentityHashMap<>();
|
||||
private int currentClassId = 1;
|
||||
private int fixedClassId = 1;
|
||||
private ClassInfo[] tracking = new ClassInfo[32];
|
||||
public static int NO_CLASS_ID = 0;
|
||||
private Map<Class, ClassInfo> store = new IdentityHashMap<>();
|
||||
private int nextClassId = 1;
|
||||
private int tempClassIdStart = 1;
|
||||
private ClassInfo[] tracking = new ClassInfo[32];
|
||||
private JfireSE jfireSE;
|
||||
private SerializerResolver resolver;
|
||||
|
||||
public ClassInfoResolver(SerializerResolver resolver, JfireSE jfireSE)
|
||||
public ClassInfoResolver(JfireSE jfireSE)
|
||||
{
|
||||
this.resolver = resolver;
|
||||
this.jfireSE = jfireSE;
|
||||
this.jfireSE = jfireSE;
|
||||
registerClass(int[].class);
|
||||
registerClass(long[].class);
|
||||
registerClass(short[].class);
|
||||
registerClass(float[].class);
|
||||
registerClass(double[].class);
|
||||
registerClass(char[].class);
|
||||
registerClass(boolean[].class);
|
||||
registerClass(byte[].class);
|
||||
registerClass(String[].class);
|
||||
registerClass(Integer[].class);
|
||||
registerClass(Long[].class);
|
||||
registerClass(Short[].class);
|
||||
registerClass(Float[].class);
|
||||
registerClass(Double[].class);
|
||||
registerClass(Character[].class);
|
||||
registerClass(Boolean[].class);
|
||||
registerClass(Byte[].class);
|
||||
}
|
||||
|
||||
public void getClassId(ClassInfo classInfo)
|
||||
{
|
||||
if (currentClassId > tracking.length)
|
||||
if (nextClassId > tracking.length)
|
||||
{
|
||||
ClassInfo[] newTracking = new ClassInfo[tracking.length << 1];
|
||||
System.arraycopy(tracking, 0, newTracking, 0, tracking.length);
|
||||
tracking = newTracking;
|
||||
}
|
||||
tracking[currentClassId] = classInfo;
|
||||
classInfo.setClassId(currentClassId);
|
||||
currentClassId += 1;
|
||||
tracking[nextClassId] = classInfo;
|
||||
classInfo.setClassId(nextClassId);
|
||||
nextClassId += 1;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
for (int i = currentClassId - 1; i > fixedClassId; i--)
|
||||
for (int i = 1; i < nextClassId; i++)
|
||||
{
|
||||
tracking[i].reset();
|
||||
tracking[i].reset(tempClassIdStart);
|
||||
}
|
||||
currentClassId = fixedClassId;
|
||||
nextClassId = tempClassIdStart;
|
||||
}
|
||||
|
||||
public ClassInfo getClassInfo(Class clazz)
|
||||
|
@ -48,7 +61,7 @@ public class ClassInfoResolver
|
|||
ClassInfo classInfo = store.get(clazz);
|
||||
if (classInfo == null)
|
||||
{
|
||||
classInfo = new ClassInfo().setClassName(clazz.getName()).setJfireSE(jfireSE).setClazz(clazz);
|
||||
classInfo = new ClassInfo().setClassName(clazz.getName()).setJfireSE(jfireSE).setRefTracking(jfireSE.isRefTracking()).setClazz(clazz);
|
||||
store.put(clazz, classInfo);
|
||||
return classInfo;
|
||||
}
|
||||
|
@ -60,24 +73,29 @@ public class ClassInfoResolver
|
|||
ClassInfo classInfo = getClassInfo(clazz);
|
||||
if (classInfo == null)
|
||||
{
|
||||
classInfo = new ClassInfo().setClassName(clazz.getName()).setJfireSE(jfireSE).setClazz(clazz);
|
||||
classInfo = new ClassInfo().setClassName(clazz.getName()).setJfireSE(jfireSE).setRefTracking(jfireSE.isRefTracking()).setClazz(clazz);
|
||||
store.put(clazz, classInfo);
|
||||
}
|
||||
for (int i = 1; i < fixedClassId; i++)
|
||||
for (int i = 1; i < tempClassIdStart; i++)
|
||||
{
|
||||
if (tracking[i].getClazz() == clazz)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (fixedClassId > tracking.length)
|
||||
if (tempClassIdStart > tracking.length)
|
||||
{
|
||||
ClassInfo[] newTracking = new ClassInfo[tracking.length << 1];
|
||||
System.arraycopy(tracking, 0, newTracking, 0, tracking.length);
|
||||
tracking = newTracking;
|
||||
}
|
||||
tracking[fixedClassId] = classInfo;
|
||||
classInfo.setClassId(fixedClassId++);
|
||||
currentClassId = fixedClassId;
|
||||
tracking[tempClassIdStart] = classInfo;
|
||||
classInfo.setClassId(tempClassIdStart++);
|
||||
nextClassId = tempClassIdStart;
|
||||
}
|
||||
|
||||
public ClassInfo getClassInfo(int classId)
|
||||
{
|
||||
return tracking[classId];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,19 +2,24 @@ package com.jfirer.se;
|
|||
|
||||
import com.jfirer.se.serializer.Serializer;
|
||||
import com.jfirer.se.serializer.SerializerResolver;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Accessors(chain = true)
|
||||
public class JfireSE
|
||||
{
|
||||
public static final byte NULL = 0;
|
||||
private boolean CYCLE_SUPPORT = true;
|
||||
private SerializerResolver serializerResolver;
|
||||
private ClassInfoResolver classInfoResolver;
|
||||
private int depth = 1;
|
||||
|
||||
public boolean isCycleSupport()
|
||||
{
|
||||
return CYCLE_SUPPORT;
|
||||
}
|
||||
public static final byte NULL = 0;
|
||||
public static final byte NOT_NULL = 1;
|
||||
@Getter
|
||||
private boolean refTracking = true;
|
||||
private SerializerResolver serializerResolver = new SerializerResolver();
|
||||
private ClassInfoResolver classInfoResolver = new ClassInfoResolver(this);
|
||||
private int depth = 1;
|
||||
private Map<String, Class<?>> classNameMap = new HashMap<>();
|
||||
private InternalByteArray byteArray = new InternalByteArray(1024);
|
||||
|
||||
public Serializer getSerializer(Class clazz)
|
||||
{
|
||||
|
@ -26,6 +31,23 @@ public class JfireSE
|
|||
return classInfoResolver.getClassInfo(clazz);
|
||||
}
|
||||
|
||||
public ClassInfo getClassInfo(String className)
|
||||
{
|
||||
Class<?> clazz = classNameMap.computeIfAbsent(className, name -> {
|
||||
try
|
||||
{
|
||||
return Class.forName(name);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
ClassInfo classInfo = getClassInfo(clazz);
|
||||
getClassId(classInfo);
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
public void getClassId(ClassInfo classInfo)
|
||||
{
|
||||
classInfoResolver.getClassId(classInfo);
|
||||
|
@ -43,4 +65,76 @@ public class JfireSE
|
|||
{
|
||||
depth--;
|
||||
}
|
||||
|
||||
public byte[] writeBytes(Object instance)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
byteArray.put(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassInfo classInfo = getClassInfo(instance.getClass());
|
||||
classInfo.writeBytes(byteArray, instance, false);
|
||||
classInfoResolver.reset();
|
||||
}
|
||||
byte[] result = byteArray.toArray();
|
||||
byteArray.setWritePosi(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object readBytes(byte[] bytes)
|
||||
{
|
||||
return readBytes(new InternalByteArray(bytes));
|
||||
}
|
||||
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
byte flag = byteArray.get();
|
||||
switch (flag)
|
||||
{
|
||||
case 0 -> {return null;}
|
||||
case 1 ->
|
||||
{
|
||||
String className = byteArray.readString();
|
||||
ClassInfo classInfo = getClassInfo(className);
|
||||
return classInfo.readBytes(byteArray, true);
|
||||
}
|
||||
case 2 ->
|
||||
{
|
||||
String className = byteArray.readString();
|
||||
ClassInfo classInfo = getClassInfo(className);
|
||||
return classInfo.readBytes(byteArray, false);
|
||||
}
|
||||
case 3, 7, 8, 9 ->
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
case 4 ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = classInfoResolver.getClassInfo(classId);
|
||||
return classInfo.readBytes(byteArray, true);
|
||||
}
|
||||
case 5 ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = classInfoResolver.getClassInfo(classId);
|
||||
return classInfo.readBytes(byteArray, false);
|
||||
}
|
||||
case 6 ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
int instanceId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = classInfoResolver.getClassInfo(classId);
|
||||
return classInfo.getTracking(instanceId);
|
||||
}
|
||||
default -> throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerClass(Class clazz)
|
||||
{
|
||||
classInfoResolver.registerClass(clazz);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,4 +5,6 @@ import com.jfirer.se.InternalByteArray;
|
|||
public interface Serializer
|
||||
{
|
||||
void writeBytes(InternalByteArray byteArray, Object instance);
|
||||
|
||||
Object readBytes(InternalByteArray byteArray);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,39 @@
|
|||
package com.jfirer.se.serializer;
|
||||
|
||||
import com.jfirer.se.InternalByteArray;
|
||||
import com.jfirer.se.JfireSE;
|
||||
import com.jfirer.se.serializer.impl.ArraySerializer;
|
||||
import com.jfirer.se.serializer.impl.ObjectSerializer;
|
||||
import io.github.karlatemp.unsafeaccessor.Unsafe;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SerializerResolver
|
||||
{
|
||||
private Map<Class, Serializer> store = new IdentityHashMap<>();
|
||||
private Map<Class, Serializer> store = new IdentityHashMap<>();
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
public SerializerResolver()
|
||||
{
|
||||
store.put(int[].class, new IntArraySerializer());
|
||||
store.put(long[].class, new LongArraySerializer());
|
||||
store.put(double[].class, new DoubleArraySerializer());
|
||||
store.put(float[].class, new FloatArraySerializer());
|
||||
store.put(short[].class, new ShortArraySerializer());
|
||||
store.put(char[].class, new CharArraySerializer());
|
||||
store.put(byte[].class, new ByteArraySerializer());
|
||||
store.put(boolean[].class, new BooleanArraySerializer());
|
||||
store.put(Integer[].class, new BoxedIntArraySerializer());
|
||||
store.put(Long[].class, new BoxedLongArraySerializer());
|
||||
store.put(Double[].class, new BoxedDoubleArraySerializer());
|
||||
store.put(Float[].class, new BoxedFloatArraySerializer());
|
||||
store.put(Short[].class, new BoxedShortArraySerializer());
|
||||
store.put(Character[].class, new BoxedCharArraySerializer());
|
||||
store.put(Byte[].class, new BoxedByteArraySerializer());
|
||||
store.put(Boolean[].class, new BoxedBooleanArraySerializer());
|
||||
store.put(String[].class, new StringArraySerializer());
|
||||
}
|
||||
|
||||
public Serializer getSerializer(Class clazz, JfireSE jfireSE)
|
||||
{
|
||||
|
@ -16,10 +42,659 @@ public class SerializerResolver
|
|||
{
|
||||
return serializer;
|
||||
}
|
||||
|
||||
if (clazz.isArray())
|
||||
{
|
||||
serializer = new ArraySerializer(clazz, jfireSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
serializer = new ObjectSerializer(clazz, jfireSE);
|
||||
}
|
||||
store.put(clazz, serializer);
|
||||
return serializer;
|
||||
}
|
||||
|
||||
public void registerSerializer(Class clazz, Serializer serializer)
|
||||
{
|
||||
store.put(clazz, serializer);
|
||||
}
|
||||
|
||||
private static int getShift(int value)
|
||||
{
|
||||
int count = 0;
|
||||
while (value != 0)
|
||||
{
|
||||
count++;
|
||||
value >>= 1;
|
||||
}
|
||||
return count-1;
|
||||
}
|
||||
|
||||
class IntArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(int[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(int[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
int[] array = (int[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
byteArray.writeVarInt(UNSAFE.getInt(array, offset + ((long) i << shift)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
int[] array = new int[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
UNSAFE.putInt(array, offset + ((long) i << shift), byteArray.readVarInt());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class LongArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(long[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(long[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
long[] array = (long[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
byteArray.writeVarLong(UNSAFE.getLong(array, offset + ((long) i << shift)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
long[] array = new long[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
UNSAFE.putLong(array, offset + ((long) i << shift), byteArray.readVarLong());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class DoubleArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(double[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(double[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
double[] array = (double[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
byteArray.writeDouble(UNSAFE.getDouble(array, offset + ((long) i << shift)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
double[] array = new double[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
UNSAFE.putDouble(array, offset + ((long) i << shift), byteArray.readDouble());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class FloatArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(float[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(float[].class) );
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
float[] array = (float[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
byteArray.writeFloat(UNSAFE.getFloat(array, offset + ((long) i << shift)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
float[] array = new float[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
UNSAFE.putFloat(array, offset + ((long) i << shift), byteArray.readFloat());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class CharArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(char[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(char[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
char[] array = (char[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
byteArray.writeVarChar(UNSAFE.getChar(array, offset + ((long) i << shift)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
char[] array = new char[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
UNSAFE.putChar(array, offset + ((long) i << shift), byteArray.readVarChar());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class ShortArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(short[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(short[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
short[] array = (short[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
byteArray.writeShort(UNSAFE.getShort(array, offset + ((long) i << shift)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
short[] array = new short[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
UNSAFE.putShort(array, offset + ((long) i << shift), byteArray.readShort());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class ByteArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(byte[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(byte[].class) );
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
byte[] array = (byte[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
byteArray.put(UNSAFE.getByte(array, offset + ((long) i << shift)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
byte[] array = new byte[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
UNSAFE.putByte(array, offset + ((long) i << shift), byteArray.get());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class BooleanArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(boolean[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(boolean[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
boolean[] array = (boolean[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
byteArray.put(UNSAFE.getBoolean(array, offset + ((long) i << shift)) ? (byte) 1 : (byte) 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
boolean[] array = new boolean[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
UNSAFE.putBoolean(array, offset + ((long) i << shift), byteArray.get() == 1);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class BoxedIntArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(Integer[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(Integer[].class) );
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
Integer[] array = (Integer[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (Integer i : array)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarInt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
Integer[] array = new Integer[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NOT_NULL)
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), byteArray.readVarInt());
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), null);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class BoxedLongArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(Long[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(Long[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
Long[] array = (Long[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (Long i : array)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarLong(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
Long[] array = new Long[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NOT_NULL)
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), byteArray.readVarLong());
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), null);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class BoxedDoubleArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(Double[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(Double[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
Double[] array = (Double[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (Double i : array)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeDouble(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
Double[] array = new Double[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NOT_NULL)
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), byteArray.readDouble());
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), null);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class BoxedFloatArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(Float[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(Float[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
Float[] array = (Float[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (Float i : array)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeFloat(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
Float[] array = new Float[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NOT_NULL)
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), byteArray.readFloat());
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), null);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class BoxedBooleanArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(Boolean[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(Boolean[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
Boolean[] array = (Boolean[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (Boolean i : array)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.put(i ? (byte) 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
Boolean[] array = new Boolean[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NOT_NULL)
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), byteArray.get() == 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), null);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class BoxedCharArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(Character[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(Character[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
Character[] array = (Character[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (Character i : array)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarChar(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
Character[] array = new Character[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NOT_NULL)
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), byteArray.readVarChar());
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), null);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class BoxedByteArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(Byte[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(Byte[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
Byte[] array = (Byte[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (Byte i : array)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.put(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
Byte[] array = new Byte[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NOT_NULL)
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), byteArray.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), null);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class BoxedShortArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(Short[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(Short[].class) );
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
Short[] array = (Short[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (Short i : array)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeShort(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
Short[] array = new Short[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NOT_NULL)
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), byteArray.readShort());
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), null);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class StringArraySerializer implements Serializer
|
||||
{
|
||||
long offset = UNSAFE.arrayBaseOffset(String[].class);
|
||||
int shift = getShift(UNSAFE.arrayIndexScale(String[].class));
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
String[] array = (String[]) instance;
|
||||
byteArray.writeVarInt(array.length);
|
||||
for (String i : array)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeString(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
String[] array = new String[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NOT_NULL)
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), byteArray.readString());
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, offset + ((long) i << shift), null);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
package com.jfirer.se.serializer.impl;
|
||||
|
||||
import com.jfirer.se.ClassInfo;
|
||||
import com.jfirer.se.InternalByteArray;
|
||||
import com.jfirer.se.JfireSE;
|
||||
import com.jfirer.se.serializer.Serializer;
|
||||
import io.github.karlatemp.unsafeaccessor.Unsafe;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ArraySerializer implements Serializer
|
||||
{
|
||||
private Class componentType;
|
||||
private int arrayBaseOffset;
|
||||
private int arrayIndexScale;
|
||||
private int arrayIndexScaleShift;
|
||||
private boolean componentTypeFinal;
|
||||
private ClassInfo classInfoOfComponentTypeFinal;
|
||||
private ClassInfo cachedClassInfo;
|
||||
private JfireSE jfireSE;
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
public ArraySerializer(Class clazz, JfireSE jfireSE)
|
||||
{
|
||||
this.jfireSE = jfireSE;
|
||||
componentType = clazz.getComponentType();
|
||||
arrayBaseOffset = UNSAFE.arrayBaseOffset(clazz);
|
||||
arrayIndexScale = UNSAFE.arrayIndexScale(clazz);
|
||||
arrayIndexScaleShift = arrayIndexScale == 4 ? 2 : 3;
|
||||
componentTypeFinal = Modifier.isFinal(componentType.getModifiers());
|
||||
if (componentTypeFinal)
|
||||
{
|
||||
classInfoOfComponentTypeFinal = jfireSE.getClassInfo(componentType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
int length = ((Object[]) instance).length;
|
||||
byteArray.writeVarInt(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
Object element = UNSAFE.getReference(instance, arrayBaseOffset + ((long) i << arrayIndexScaleShift));
|
||||
if (element == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (componentTypeFinal)
|
||||
{
|
||||
classInfoOfComponentTypeFinal.writeBytes(byteArray, element, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cachedClassInfo != null && cachedClassInfo.getClazz() == element.getClass())
|
||||
{
|
||||
cachedClassInfo.writeBytes(byteArray, element, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
cachedClassInfo = jfireSE.getClassInfo(element.getClass());
|
||||
cachedClassInfo.writeBytes(byteArray, element, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
Object array = Array.newInstance(componentType, length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (componentTypeFinal)
|
||||
{
|
||||
int flag = byteArray.readVarInt();
|
||||
switch (flag)
|
||||
{
|
||||
case JfireSE.NULL -> UNSAFE.putReference(array, arrayBaseOffset + ((long) i << arrayIndexScaleShift), null);
|
||||
case 7 -> UNSAFE.putReference(array, arrayBaseOffset + ((long) i << arrayIndexScaleShift), classInfoOfComponentTypeFinal.readBytes(byteArray, true));
|
||||
case 8 -> UNSAFE.putReference(array, arrayBaseOffset + ((long) i << arrayIndexScaleShift), classInfoOfComponentTypeFinal.readBytes(byteArray, false));
|
||||
case 9 -> UNSAFE.putReference(array, arrayBaseOffset + ((long) i << arrayIndexScaleShift), classInfoOfComponentTypeFinal.getTracking(byteArray.readVarInt()));
|
||||
default -> throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, arrayBaseOffset + ((long) i << arrayIndexScaleShift), jfireSE.readBytes(byteArray));
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
|
@ -6,23 +6,25 @@ import com.jfirer.se.ClassInfo;
|
|||
import com.jfirer.se.InternalByteArray;
|
||||
import com.jfirer.se.JfireSE;
|
||||
import com.jfirer.se.serializer.Serializer;
|
||||
import io.github.karlatemp.unsafeaccessor.Unsafe;
|
||||
import lombok.Data;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ObjectSerializer implements Serializer
|
||||
{
|
||||
private FieldInfo[] primitiveFieldInfos;
|
||||
private FieldInfo[] boxFieldInfos;
|
||||
private FinalFieldInfo[] finalFieldInfos;
|
||||
private JfireSE jfireSE;
|
||||
private Class clazz;
|
||||
private FieldInfo[] primitiveFieldInfos;
|
||||
private FieldInfo[] boxFieldInfos;
|
||||
private FinalFieldInfo[] finalFieldInfos;
|
||||
private VariableFieldInfo[] variableFieldInfos;
|
||||
private JfireSE jfireSE;
|
||||
private Class clazz;
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
public ObjectSerializer(Class clazz, JfireSE jfireSE)
|
||||
{
|
||||
|
@ -33,19 +35,69 @@ public class ObjectSerializer implements Serializer
|
|||
while (type != Object.class)
|
||||
{
|
||||
fields.addAll(Arrays.stream(type.getDeclaredFields()).filter(Predicate.not(field -> Modifier.isStatic(field.getModifiers()))).toList());
|
||||
type = type.getComponentType();
|
||||
type = type.getSuperclass();
|
||||
}
|
||||
primitiveFieldInfos = fields.stream().filter(field -> field.getType().isPrimitive()).sorted(Comparator.comparing(o -> o.getType().getName())).map(FieldInfo::new).toArray(FieldInfo[]::new);
|
||||
boxFieldInfos = fields.stream().filter(field -> ReflectUtil.isPrimitiveBox(field.getType()) || field.getType() == String.class).sorted(Comparator.comparing(o -> o.getType().getName())).map(FieldInfo::new).toArray(FieldInfo[]::new);
|
||||
finalFieldInfos = fields.stream().filter(Predicate.not(field -> ReflectUtil.isPrimitiveBox(field.getType())))//
|
||||
.filter(Predicate.not(field -> ReflectUtil.isPrimitive(field.getType())))//
|
||||
.filter(field -> field.getType() != String.class)//
|
||||
.filter(field -> field.getType() != void.class && field.getType() != Void.class)//
|
||||
.filter(field -> Modifier.isFinal(field.getType().getModifiers())).sorted(Comparator.comparing(o -> o.getType().getName())).map(FinalFieldInfo::new).toArray(FinalFieldInfo[]::new);
|
||||
.filter(field -> Modifier.isFinal(field.getType().getModifiers()))//
|
||||
.sorted(Comparator.comparing(o -> o.getType().getName()))//
|
||||
.map(FinalFieldInfo::new).toArray(FinalFieldInfo[]::new);
|
||||
variableFieldInfos = fields.stream().filter(Predicate.not(field -> ReflectUtil.isPrimitiveBox(field.getType())))//
|
||||
.filter(Predicate.not(field -> ReflectUtil.isPrimitive(field.getType())))//
|
||||
.filter(field -> field.getType() != String.class)//
|
||||
.filter(field -> field.getType() != void.class && field.getType() != Void.class)//
|
||||
.filter(field -> !Modifier.isFinal(field.getType().getModifiers()))//
|
||||
.sorted(Comparator.comparing(o -> o.getType().getName()))//
|
||||
.map(VariableFieldInfo::new).toArray(VariableFieldInfo[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
for (FieldInfo primitiveFieldInfo : primitiveFieldInfos)
|
||||
{
|
||||
primitiveFieldInfo.write(byteArray, instance);
|
||||
}
|
||||
for (FieldInfo boxFieldInfo : boxFieldInfos)
|
||||
{
|
||||
boxFieldInfo.write(byteArray, instance);
|
||||
}
|
||||
for (FinalFieldInfo finalFieldInfo : finalFieldInfos)
|
||||
{
|
||||
finalFieldInfo.write(byteArray, instance);
|
||||
}
|
||||
for (VariableFieldInfo variableFieldInfo : variableFieldInfos)
|
||||
{
|
||||
variableFieldInfo.write(byteArray, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public Object readBytes(InternalByteArray byteArray)
|
||||
{
|
||||
Object instance = UNSAFE.allocateInstance(clazz);
|
||||
for (FieldInfo primitiveFieldInfo : primitiveFieldInfos)
|
||||
{
|
||||
primitiveFieldInfo.read(byteArray, instance);
|
||||
}
|
||||
for (FieldInfo boxFieldInfo : boxFieldInfos)
|
||||
{
|
||||
boxFieldInfo.read(byteArray, instance);
|
||||
}
|
||||
for (FinalFieldInfo finalFieldInfo : finalFieldInfos)
|
||||
{
|
||||
finalFieldInfo.read(byteArray, instance);
|
||||
}
|
||||
for (VariableFieldInfo variableFieldInfo : variableFieldInfos)
|
||||
{
|
||||
variableFieldInfo.read(byteArray, instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Data
|
||||
|
@ -60,6 +112,120 @@ public class ObjectSerializer implements Serializer
|
|||
accessor = new ValueAccessor(field);
|
||||
}
|
||||
|
||||
void read(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
switch (classId)
|
||||
{
|
||||
case ReflectUtil.PRIMITIVE_INT -> accessor.set(instance, byteArray.readVarInt());
|
||||
case ReflectUtil.PRIMITIVE_LONG -> accessor.set(instance, byteArray.readVarLong());
|
||||
case ReflectUtil.PRIMITIVE_FLOAT -> accessor.set(instance, byteArray.readFloat());
|
||||
case ReflectUtil.PRIMITIVE_DOUBLE -> accessor.set(instance, byteArray.readDouble());
|
||||
case ReflectUtil.PRIMITIVE_BOOL -> accessor.set(instance, byteArray.readPositive() == 1);
|
||||
case ReflectUtil.PRIMITIVE_CHAR -> accessor.set(instance, byteArray.readVarChar());
|
||||
case ReflectUtil.PRIMITIVE_SHORT -> accessor.set(instance, byteArray.readShort());
|
||||
case ReflectUtil.PRIMITIVE_BYTE -> accessor.set(instance, byteArray.get());
|
||||
case ReflectUtil.CLASS_INT ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readVarInt());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_LONG ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readVarLong());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_FLOAT ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readFloat());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_DOUBLE ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readDouble());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_BOOL ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readPositive() == 1);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_CHAR ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readVarChar());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_SHORT ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readShort());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_BYTE ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.get());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_STRING ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.setObject(instance, byteArray.readString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
switch (classId)
|
||||
|
@ -81,7 +247,7 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 01);
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarInt(value);
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +260,7 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 01);
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarLong(value);
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +273,7 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 01);
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeFloat(value);
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +286,7 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 01);
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeDouble(value);
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +299,7 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 01);
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writePositive(value ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +312,7 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 01);
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarChar(value);
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +325,7 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 01);
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeShort(value);
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +338,7 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 01);
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.put(value);
|
||||
}
|
||||
}
|
||||
|
@ -185,10 +351,11 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 01);
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeString(value);
|
||||
}
|
||||
}
|
||||
default -> throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,8 +380,20 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 07);
|
||||
classInfo.writeBytes(byteArray, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void read(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
byte flag = byteArray.get();
|
||||
switch (flag)
|
||||
{
|
||||
case JfireSE.NULL -> accessor.setObject(instance, null);
|
||||
case 7 -> accessor.setObject(instance, classInfo.readBytes(byteArray, true));
|
||||
case 8 -> accessor.setObject(instance, classInfo.readBytes(byteArray, false));
|
||||
case 9 -> accessor.setObject(instance, classInfo.getTracking(byteArray.readVarInt()));
|
||||
default -> throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,5 +407,31 @@ public class ObjectSerializer implements Serializer
|
|||
{
|
||||
accessor = new ValueAccessor(field);
|
||||
}
|
||||
|
||||
void write(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
return;
|
||||
}
|
||||
Class<?> clazz = instance.getClass();
|
||||
if (classInfo != null && classInfo.getClazz() == clazz)
|
||||
{
|
||||
classInfo.writeBytes(byteArray, instance, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
classInfo = jfireSE.getClassInfo(clazz);
|
||||
classInfo.writeBytes(byteArray, instance, false);
|
||||
}
|
||||
}
|
||||
|
||||
void read(InternalByteArray byteArray, Object instance)
|
||||
{
|
||||
accessor.setObject(instance, jfireSE.readBytes(byteArray));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
package org.example;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
*/
|
||||
public class AppTest
|
||||
extends TestCase
|
||||
{
|
||||
/**
|
||||
* Create the test case
|
||||
*
|
||||
* @param testName name of the test case
|
||||
*/
|
||||
public AppTest( String testName )
|
||||
{
|
||||
super( testName );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the suite of tests being tested
|
||||
*/
|
||||
public static Test suite()
|
||||
{
|
||||
return new TestSuite( AppTest.class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rigourous Test :-)
|
||||
*/
|
||||
public void testApp()
|
||||
{
|
||||
assertTrue( true );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package org.example;
|
||||
|
||||
import com.jfirer.fse.ByteArray;
|
||||
import com.jfirer.fse.Fse;
|
||||
import com.jfirer.se.JfireSE;
|
||||
import io.fury.Fury;
|
||||
import io.fury.config.Language;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import org.openjdk.jmh.runner.Runner;
|
||||
import org.openjdk.jmh.runner.RunnerException;
|
||||
import org.openjdk.jmh.runner.options.Options;
|
||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@Warmup(iterations = 2, time = 1)
|
||||
@Measurement(iterations = 3, time = 3)
|
||||
@OutputTimeUnit(TimeUnit.SECONDS)
|
||||
@Fork(1)
|
||||
@State(Scope.Benchmark)
|
||||
public class BenchMark
|
||||
{
|
||||
Fse fse = new Fse();
|
||||
Fse fse_3 = new Fse().useCompile();
|
||||
TestData data = new TestData();
|
||||
ByteArray buf = ByteArray.allocate(100);
|
||||
Fury fury = Fury.builder().withLanguage(Language.JAVA)//
|
||||
.requireClassRegistration(false)//
|
||||
.withRefTracking(true).build();
|
||||
JfireSE jfireSE = new JfireSE();
|
||||
|
||||
@Setup
|
||||
public void before(){
|
||||
jfireSE.registerClass(TestData.class);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testNoCompile()
|
||||
{
|
||||
buf.clear();
|
||||
fse.serialize(data, buf);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testFury()
|
||||
{
|
||||
byte[] bytes = fury.serialize(data);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testDirectCompile()
|
||||
{
|
||||
buf.clear();
|
||||
fse_3.serialize(data, buf);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testJfireSE()
|
||||
{
|
||||
jfireSE.writeBytes(data);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws RunnerException
|
||||
{
|
||||
Options opt = new OptionsBuilder().include(BenchMark.class.getSimpleName()).build();
|
||||
new Runner(opt).run();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package org.example;
|
||||
|
||||
import com.jfirer.se.JfireSE;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class FunctionTest
|
||||
{
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
JfireSE jfireSE = new JfireSE();
|
||||
TestData data = new TestData();
|
||||
//创建一个二进制数组容器,用于容纳序列化后的输出。容器大小会在需要时自动扩大,入参仅决定初始化大小。
|
||||
//执行序列化,会将序列化对象序列化到二进制数组容器之中。
|
||||
byte[] bytes = jfireSE.writeBytes(data);
|
||||
TestData result = (TestData) jfireSE.readBytes(bytes);
|
||||
assertTrue(result.equals(data));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2()
|
||||
{
|
||||
TestData data = new TestData();
|
||||
JfireSE jfireSE = new JfireSE();
|
||||
byte[] bytes = jfireSE.writeBytes(data);
|
||||
Object o = jfireSE.readBytes(bytes);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package org.example;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class TestData implements Serializable
|
||||
{
|
||||
private int a = 213212312;
|
||||
private boolean b = false;
|
||||
private char c = 'c';
|
||||
private byte d = 0x11;
|
||||
private short e = 24;
|
||||
private long f = 1213124131312321L;
|
||||
private double g = 231321.2132;
|
||||
private float h = (float) 4986.2;
|
||||
// private String i = "123452312316789a";
|
||||
// private int[] j = new int[]{1, 2, 4, 5};
|
||||
// private boolean[] k = new boolean[]{true, false, true, false, false, false, true};
|
||||
// private char[] l = new char[]{'a', 'v', 'q', 'j', 'h', 'e', 'f'};
|
||||
// private byte[] m = new byte[]{0x32, 0x12, 0x34, (byte) 0x96};
|
||||
// private short[] n = new short[]{3, 8, 213, 451, 312, 45};
|
||||
// private long[] o = new long[]{12313131313l, 524141431313l, 3131231231425l, 1313123121l};
|
||||
// private double[] p = new double[]{6468613646.48646d, 4646.456d, 546864648867.466d};
|
||||
// private float[] q = new float[]{46486.2f, 49849.2f, 646854.6f};
|
||||
// private String[] r = new String[]{"abcdf12345", "abdfcgf12323"};
|
||||
|
||||
public boolean equals(Object x)
|
||||
{
|
||||
if (x instanceof TestData)
|
||||
{
|
||||
TestData target = (TestData) x;
|
||||
// if (target.a == a && target.b == b && target.c == c && target.d == d && target.e == e && target.f == f && target.g == g && target.h == h && target.i.equals(i))
|
||||
// {
|
||||
// for (int i = 0; i < target.j.length; i++)
|
||||
// {
|
||||
// if (target.j[i] != j[i])
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// for (int i = 0; i < k.length; i++)
|
||||
// {
|
||||
// if (target.k[i] != k[i])
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// for (int i = 0; i < l.length; i++)
|
||||
// {
|
||||
// if (target.l[i] != l[i])
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// for (int i = 0; i < m.length; i++)
|
||||
// {
|
||||
// if (target.m[i] != m[i])
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// for (int i = 0; i < n.length; i++)
|
||||
// {
|
||||
// if (target.n[i] != n[i])
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// for (int i = 0; i < o.length; i++)
|
||||
// {
|
||||
// if (target.o[i] != o[i])
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// for (int i = 0; i < p.length; i++)
|
||||
// {
|
||||
// if (p[i] != target.p[i])
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// for (int i = 0; i < r.length; i++)
|
||||
// {
|
||||
// if (target.r[i].equals(r[i]) == false)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// for (int i = 0; i < q.length; i++)
|
||||
// {
|
||||
// if (q[i] != target.q[i])
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue