功能完善,并且提供了一个编译输出的版本,性能强大。在简单类的测试中,超过了 Fury
parent
ab14e5b94d
commit
9a44742544
2
pom.xml
2
pom.xml
|
@ -37,7 +37,7 @@
|
|||
<dependency>
|
||||
<groupId>com.jfirer</groupId>
|
||||
<artifactId>baseutil</artifactId>
|
||||
<version>1.1.7-SNAPSHOT</version>
|
||||
<version>1.1.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
|
|
@ -4,7 +4,10 @@ import com.jfirer.baseutil.reflect.ReflectUtil;
|
|||
import com.jfirer.fse.InternalByteArray;
|
||||
import io.github.karlatemp.unsafeaccessor.Unsafe;
|
||||
|
||||
import java.lang.invoke.*;
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
|
@ -802,7 +805,7 @@ public class ByteArray
|
|||
ensureNewWriterIndex(idx + 8 + numBytes);
|
||||
idx += writePositiveVarIntWithoutEnsure(numBytes);
|
||||
final long destAddr = BYTE_ARRAY_OFFSET + idx;
|
||||
copyMemory(arr, arrOffset, array, destAddr, numBytes);
|
||||
copyMemory(arr, BYTE_ARRAY_OFFSET + arrOffset, array, destAddr, numBytes);
|
||||
writerIndex = idx + numBytes;
|
||||
}
|
||||
|
||||
|
@ -816,7 +819,7 @@ public class ByteArray
|
|||
throw new IndexOutOfBoundsException(String.format("readerIndex(%d) + length(%d) exceeds size(%d): %s", readerIdx, numBytes, writerIndex, this));
|
||||
}
|
||||
final byte[] arr = new byte[numBytes];
|
||||
System.arraycopy(array, BYTE_ARRAY_OFFSET + readerIdx, arr, 0, numBytes);
|
||||
System.arraycopy(array, readerIdx, arr, 0, numBytes);
|
||||
readerIndex = readerIdx + numBytes;
|
||||
return arr;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ public class JfireSEConfig
|
|||
|
||||
private StaticClasInfo resolve(Class<?> clazz)
|
||||
{
|
||||
StaticClasInfo staticClasInfo = new StaticClasInfo(staticClassId, clazz.getName(), clazz, refTracking);
|
||||
StaticClasInfo staticClasInfo = new StaticClasInfo(staticClassId, clazz, refTracking);
|
||||
staticClassId++;
|
||||
return staticClasInfo;
|
||||
}
|
||||
|
|
|
@ -6,21 +6,27 @@ import com.jfirer.se2.classinfo.StaticClasInfo;
|
|||
import com.jfirer.se2.serializer.Serializer;
|
||||
import com.jfirer.se2.serializer.SerializerFactory;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class JfireSEImpl implements JfireSE
|
||||
{
|
||||
private final boolean refTracking;
|
||||
private final int staticClassId;
|
||||
private int dyncmicClassId;
|
||||
private final boolean refTracking;
|
||||
private final int staticClassId;
|
||||
private int dyncmicClassId;
|
||||
/**
|
||||
* 用于存储序列化相关的 classInfo
|
||||
*/
|
||||
private ClassInfo[] serializedClassInfos;
|
||||
private ClassInfo[] serializedClassInfos;
|
||||
/**
|
||||
* 用于存储逆序列化过程中的临时信息
|
||||
*/
|
||||
private ClassInfo[] deSerializedClassInfos;
|
||||
private SerializerFactory serializerFactory = new SerializerFactory();
|
||||
private ByteArray byteArray = new ByteArray(1000);
|
||||
private ClassInfo[] deSerializedClassInfos;
|
||||
private SerializerFactory serializerFactory = new SerializerFactory();
|
||||
private ByteArray byteArray = new ByteArray(1000);
|
||||
private ClassInfo classInfoCache;
|
||||
private Map<Class<?>, ClassInfo> classInfoMap = new HashMap<>();
|
||||
|
||||
public JfireSEImpl(boolean refTracking, StaticClasInfo[] staticClasInfos)
|
||||
{
|
||||
|
@ -35,12 +41,15 @@ public class JfireSEImpl implements JfireSE
|
|||
|
||||
public ClassInfo getForSerialize(Class<?> clazz)
|
||||
{
|
||||
for (int i = 0; i < dyncmicClassId; i++)
|
||||
if (classInfoCache != null && classInfoCache.getClazz() == clazz)
|
||||
{
|
||||
if (serializedClassInfos[i].getClazz() == clazz)
|
||||
{
|
||||
return serializedClassInfos[i];
|
||||
}
|
||||
return classInfoCache;
|
||||
}
|
||||
ClassInfo classInfo = classInfoMap.get(clazz);
|
||||
if (classInfo != null)
|
||||
{
|
||||
classInfoCache = classInfo;
|
||||
return classInfo;
|
||||
}
|
||||
if (dyncmicClassId == serializedClassInfos.length)
|
||||
{
|
||||
|
@ -48,11 +57,12 @@ public class JfireSEImpl implements JfireSE
|
|||
System.arraycopy(serializedClassInfos, 0, tmp, 0, serializedClassInfos.length);
|
||||
serializedClassInfos = tmp;
|
||||
}
|
||||
DynamicClassInfo dynamicClassInfo = new DynamicClassInfo((short) dyncmicClassId, clazz.getName(), clazz, refTracking);
|
||||
DynamicClassInfo dynamicClassInfo = new DynamicClassInfo((short) dyncmicClassId, clazz, refTracking);
|
||||
serializedClassInfos[dyncmicClassId] = dynamicClassInfo;
|
||||
dyncmicClassId++;
|
||||
Serializer serializer = serializerFactory.getSerializer(clazz, this);
|
||||
dynamicClassInfo.setSerializer(serializer);
|
||||
classInfoCache = dynamicClassInfo;
|
||||
return dynamicClassInfo;
|
||||
}
|
||||
|
||||
|
@ -95,36 +105,67 @@ public class JfireSEImpl implements JfireSE
|
|||
{
|
||||
case JfireSE.NAME_ID_CONTENT_TRACK ->
|
||||
{
|
||||
String className = byteArray.readString();
|
||||
int classId = byteArray.readVarInt();
|
||||
try
|
||||
{
|
||||
Class<?> clazz = Class.forName(className);
|
||||
ClassInfo classInfo = getForSerialize(clazz);
|
||||
if (deSerializedClassInfos == null)
|
||||
{
|
||||
deSerializedClassInfos = new ClassInfo[classId + 1];
|
||||
deSerializedClassInfos[classId] = classInfo;
|
||||
}
|
||||
else if (classId >= deSerializedClassInfos.length)
|
||||
{
|
||||
int newLen = deSerializedClassInfos.length * 2;
|
||||
newLen = newLen > classId ? newLen : classId + 1;
|
||||
ClassInfo[] tmp = new ClassInfo[newLen];
|
||||
System.arraycopy(deSerializedClassInfos, 0, tmp, 0, deSerializedClassInfos.length);
|
||||
deSerializedClassInfos = tmp;
|
||||
deSerializedClassInfos[classId] = classInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
deSerializedClassInfos[classId] = classInfo;
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
byte[] classNameBytes = stream.readBytesWithSizeEmbedded();
|
||||
int classId = stream.readVarInt();
|
||||
ClassInfo classInfo = getForDeSerialize(classNameBytes, classId);
|
||||
return classInfo.readWithTrack(stream);
|
||||
}
|
||||
case JfireSE.NAME_ID_CONTENT_UN_TRACK ->
|
||||
{
|
||||
byte[] classNameBytes = stream.readBytesWithSizeEmbedded();
|
||||
int classId = stream.readVarInt();
|
||||
return getForDeSerialize(classNameBytes, classId).readWithoutTrack(stream);
|
||||
}
|
||||
case JfireSE.id_content_track ->
|
||||
{
|
||||
int classId = stream.readVarInt();
|
||||
ClassInfo classInfo = getForDeSerialize(classId);
|
||||
return classInfo.readWithTrack(stream);
|
||||
}
|
||||
case JfireSE.id_content_un_track ->
|
||||
{
|
||||
int classId = stream.readVarInt();
|
||||
ClassInfo classInfo = getForDeSerialize(classId);
|
||||
return classInfo.readWithoutTrack(stream);
|
||||
}
|
||||
default -> throw new RuntimeException("未知的序列化类型");
|
||||
}
|
||||
}
|
||||
|
||||
public ClassInfo getForDeSerialize(byte[] classNameBytes, int classId)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> clazz = Class.forName(new String(classNameBytes, StandardCharsets.UTF_8));
|
||||
ClassInfo classInfo = getForSerialize(clazz);
|
||||
if (deSerializedClassInfos == null)
|
||||
{
|
||||
deSerializedClassInfos = new ClassInfo[classId + 1];
|
||||
deSerializedClassInfos[classId] = classInfo;
|
||||
}
|
||||
else if (classId >= deSerializedClassInfos.length)
|
||||
{
|
||||
int newLen = deSerializedClassInfos.length * 2;
|
||||
newLen = newLen > classId ? newLen : classId + 1;
|
||||
ClassInfo[] tmp = new ClassInfo[newLen];
|
||||
System.arraycopy(deSerializedClassInfos, 0, tmp, 0, deSerializedClassInfos.length);
|
||||
deSerializedClassInfos = tmp;
|
||||
deSerializedClassInfos[classId] = classInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
deSerializedClassInfos[classId] = classInfo;
|
||||
}
|
||||
return classInfo;
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassInfo getForDeSerialize(int classId)
|
||||
{
|
||||
return deSerializedClassInfos[classId];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,20 +3,31 @@ package com.jfirer.se2.classinfo;
|
|||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import com.jfirer.se2.serializer.Serializer;
|
||||
import io.github.karlatemp.unsafeaccessor.Unsafe;
|
||||
import lombok.Data;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Data
|
||||
public abstract class ClassInfo
|
||||
{
|
||||
protected final short classId;
|
||||
protected final String className;
|
||||
protected final Class<?> clazz;
|
||||
protected final boolean refTrack;
|
||||
protected Object[] tracking;
|
||||
protected int refTrackingIndex = 0;
|
||||
protected Serializer serializer;
|
||||
protected final short classId;
|
||||
protected final byte[] classNameBytes;
|
||||
protected final Class<?> clazz;
|
||||
protected final boolean refTrack;
|
||||
protected Object[] tracking;
|
||||
protected int refTrackingIndex = 0;
|
||||
protected Serializer serializer;
|
||||
protected static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
public ClassInfo(short classId, Class<?> clazz, boolean refTrack)
|
||||
{
|
||||
this.classId = classId;
|
||||
this.clazz = clazz;
|
||||
this.refTrack = refTrack;
|
||||
classNameBytes = clazz.getName().getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public int addTracking(Object instance)
|
||||
{
|
||||
|
@ -75,5 +86,43 @@ public abstract class ClassInfo
|
|||
}
|
||||
}
|
||||
|
||||
public abstract void readWithTrack(ByteArray byteArray);
|
||||
/**
|
||||
* 读取对象的内容,并且这个对象本身要放入追踪
|
||||
*
|
||||
* @param byteArray
|
||||
* @return
|
||||
*/
|
||||
public Object readWithTrack(ByteArray byteArray)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object instance = UNSAFE.allocateInstance(clazz);
|
||||
addTracking(instance);
|
||||
serializer.read(byteArray, instance);
|
||||
return instance;
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readWithoutTrack(ByteArray byteArray)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object instance = UNSAFE.allocateInstance(clazz);
|
||||
serializer.read(byteArray, instance);
|
||||
return instance;
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object getInstanceById(int instanceId)
|
||||
{
|
||||
return tracking[instanceId];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@ public class DynamicClassInfo extends ClassInfo
|
|||
*/
|
||||
private boolean firstSerialized = true;
|
||||
|
||||
public DynamicClassInfo(short classId, String className, Class<?> clazz, boolean refTracking)
|
||||
public DynamicClassInfo(short classId, Class<?> clazz, boolean refTracking)
|
||||
{
|
||||
super(classId, className, clazz, refTracking);
|
||||
super(classId, clazz, refTracking);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -38,7 +38,7 @@ public class DynamicClassInfo extends ClassInfo
|
|||
firstSerialized = true;
|
||||
addTracking(instance);
|
||||
byteArray.put(JfireSE.NAME_ID_CONTENT_TRACK);
|
||||
byteArray.writeString(className);
|
||||
byteArray.writeBytesWithSizeEmbedded(classNameBytes);
|
||||
byteArray.writeVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ public class DynamicClassInfo extends ClassInfo
|
|||
{
|
||||
firstSerialized = true;
|
||||
byteArray.put(JfireSE.NAME_ID_CONTENT_UN_TRACK);
|
||||
byteArray.writeString(className);
|
||||
byteArray.writeBytesWithSizeEmbedded(classNameBytes);
|
||||
byteArray.writeVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ import com.jfirer.se2.JfireSE;
|
|||
|
||||
public class StaticClasInfo extends ClassInfo
|
||||
{
|
||||
public StaticClasInfo(short classId, String className, Class<?> clazz, boolean refTracking)
|
||||
public StaticClasInfo(short classId, Class<?> clazz, boolean refTracking)
|
||||
{
|
||||
super(classId, className, clazz, refTracking);
|
||||
super(classId, clazz, refTracking);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteArray byteArray, Object instance)
|
||||
public void write(ByteArray byteArray, Object instance)
|
||||
{
|
||||
if (refTrack)
|
||||
{
|
||||
|
@ -36,4 +36,10 @@ public class StaticClasInfo extends ClassInfo
|
|||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readWithTrack(ByteArray byteArray)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,5 +6,7 @@ public interface Serializer
|
|||
{
|
||||
void writeBytes(ByteArray byteArray, Object instance);
|
||||
|
||||
Object read(ByteArray stream);
|
||||
void read(ByteArray stream, Object instance);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,9 @@ public class SerializerFactory
|
|||
|
||||
public Serializer getSerializer(Class<?> clazz, JfireSEImpl jfireSE)
|
||||
{
|
||||
return store.putIfAbsent(clazz, new ObjectSerializer(clazz, jfireSE));
|
||||
// ObjectSerializer objectSerializer = new ObjectSerializer(clazz, jfireSE);
|
||||
Serializer objectSerializer = ObjectSerializer.buildCompileVersion(clazz, jfireSE);
|
||||
store.putIfAbsent(clazz, objectSerializer);
|
||||
return objectSerializer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
|
||||
|
@ -11,7 +10,7 @@ public class BoxedFieldInfo extends FieldInfo
|
|||
{
|
||||
public BoxedFieldInfo(Field field)
|
||||
{
|
||||
super(ReflectUtil.getClassId(field.getType()), new ValueAccessor(field));
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,4 +138,77 @@ public class BoxedFieldInfo extends FieldInfo
|
|||
default -> throw new RuntimeException("不支持的类型");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteArray byteArray, Object instance)
|
||||
{
|
||||
boolean exist = byteArray.get() == JfireSE.NOT_NULL;
|
||||
switch (classId)
|
||||
{
|
||||
case ReflectUtil.CLASS_BOOL ->
|
||||
{
|
||||
if (exist)
|
||||
{
|
||||
accessor.setObject(instance, byteArray.readBoolean());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_BYTE ->
|
||||
{
|
||||
if (exist)
|
||||
{
|
||||
accessor.setObject(instance, byteArray.get());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_CHAR ->
|
||||
{
|
||||
if (exist)
|
||||
{
|
||||
accessor.setObject(instance, byteArray.readChar());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_SHORT ->
|
||||
{
|
||||
if (exist)
|
||||
{
|
||||
accessor.setObject(instance, (short) byteArray.readVarInt());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_INT ->
|
||||
{
|
||||
if (exist)
|
||||
{
|
||||
accessor.setObject(instance, byteArray.readVarInt());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_LONG ->
|
||||
{
|
||||
if (exist)
|
||||
{
|
||||
accessor.setObject(instance, byteArray.readVarLong());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_FLOAT ->
|
||||
{
|
||||
if (exist)
|
||||
{
|
||||
accessor.setObject(instance, byteArray.readFloat());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_DOUBLE ->
|
||||
{
|
||||
if (exist)
|
||||
{
|
||||
accessor.setObject(instance, byteArray.readDouble());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_STRING ->
|
||||
{
|
||||
if (exist)
|
||||
{
|
||||
accessor.setObject(instance, byteArray.readString());
|
||||
}
|
||||
}
|
||||
default -> throw new RuntimeException("不支持的类型");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,27 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.baseutil.smc.compiler.CompileHelper;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public abstract class FieldInfo
|
||||
{
|
||||
protected int classId;
|
||||
protected ValueAccessor accessor;
|
||||
protected final int classId;
|
||||
protected final ValueAccessor accessor;
|
||||
private static final CompileHelper COMPILE_HELPER = new CompileHelper();
|
||||
protected Field field;
|
||||
|
||||
public FieldInfo(int classId, ValueAccessor accessor)
|
||||
public FieldInfo(Field field)
|
||||
{
|
||||
this.classId = classId;
|
||||
this.accessor = accessor;
|
||||
this.classId = ReflectUtil.getClassId(field.getType());
|
||||
this.accessor = new ValueAccessor(field);
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public abstract void write(ByteArray byteArray, Object instance);
|
||||
|
||||
public abstract void read(ByteArray byteArray, Object instance);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import com.jfirer.se2.JfireSEImpl;
|
||||
|
@ -11,12 +9,14 @@ import java.lang.reflect.Field;
|
|||
|
||||
public class FinalFieldInfo extends FieldInfo
|
||||
{
|
||||
private ClassInfo classInfo;
|
||||
private ClassInfo classInfo;
|
||||
private JfireSEImpl jfireSE;
|
||||
|
||||
public FinalFieldInfo(Field field, JfireSEImpl jfireSE)
|
||||
{
|
||||
super(ReflectUtil.getClassId(field.getType()), new ValueAccessor(field));
|
||||
classInfo = jfireSE.getForSerialize(field.getType());
|
||||
super(field);
|
||||
classInfo = jfireSE.getForSerialize(field.getType());
|
||||
this.jfireSE = jfireSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -32,4 +32,37 @@ public class FinalFieldInfo extends FieldInfo
|
|||
classInfo.writeKnownClazz(byteArray, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteArray byteArray, Object instance)
|
||||
{
|
||||
byte flag = byteArray.get();
|
||||
if (flag == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
case JfireSE.instance_id ->
|
||||
{
|
||||
int instanceId = byteArray.readVarInt();
|
||||
Object property = classInfo.getInstanceById(instanceId);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.content_track ->
|
||||
{
|
||||
Object property = classInfo.readWithTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.content_un_track ->
|
||||
{
|
||||
Object property = classInfo.readWithoutTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
default -> throw new RuntimeException("flag:" + flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,54 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.smc.compiler.CompileHelper;
|
||||
import com.jfirer.baseutil.smc.model.ClassModel;
|
||||
import com.jfirer.baseutil.smc.model.ConstructorModel;
|
||||
import com.jfirer.baseutil.smc.model.FieldModel;
|
||||
import com.jfirer.baseutil.smc.model.MethodModel;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSEImpl;
|
||||
import com.jfirer.se2.serializer.Serializer;
|
||||
import io.github.karlatemp.unsafeaccessor.Unsafe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ObjectSerializer implements Serializer
|
||||
{
|
||||
private Class<?> clazz;
|
||||
private FieldInfo[] fieldInfos;
|
||||
private Class<?> clazz;
|
||||
private FieldInfo[] fieldInfos;
|
||||
static int COMPILE_COUNT = 1;
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
public ObjectSerializer(Class<?> clazz, JfireSEImpl jfireSE)
|
||||
{
|
||||
fieldInfos = parse(clazz, jfireSE).toArray(FieldInfo[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(ByteArray byteArray, Object instance)
|
||||
{
|
||||
for (FieldInfo each : fieldInfos)
|
||||
{
|
||||
each.write(byteArray, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteArray stream, Object instance)
|
||||
{
|
||||
for (FieldInfo each : fieldInfos)
|
||||
{
|
||||
each.read(stream, instance);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<FieldInfo> parse(Class<?> clazz, JfireSEImpl jfireSE)
|
||||
{
|
||||
Class type = clazz;
|
||||
List<Field> fields = new ArrayList<>();
|
||||
|
@ -53,15 +86,159 @@ public class ObjectSerializer implements Serializer
|
|||
list.addAll(boxedFieldInfos);
|
||||
list.addAll(finalFieldInfos);
|
||||
list.addAll(variableFieldInfos);
|
||||
fieldInfos = list.toArray(FieldInfo[]::new);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(ByteArray byteArray, Object instance)
|
||||
public static Serializer buildCompileVersion(Class<?> clazz, JfireSEImpl jfireSE)
|
||||
{
|
||||
for (FieldInfo each : fieldInfos)
|
||||
List<FieldInfo> parse = parse(clazz, jfireSE);
|
||||
ClassModel classModel = new ClassModel("ObjectSerializer_compile_" + COMPILE_COUNT);
|
||||
COMPILE_COUNT++;
|
||||
classModel.addInterface(Serializer.class);
|
||||
classModel.addImport(Unsafe.class);
|
||||
classModel.addImport(List.class);
|
||||
classModel.addImport(FieldInfo.class);
|
||||
classModel.addImport(ByteArray.class);
|
||||
classModel.addField(new FieldModel("UNSAFE", Unsafe.class, "Unsafe.getUnsafe()", classModel));
|
||||
ConstructorModel constructorModel = new ConstructorModel(classModel);
|
||||
constructorModel.setParamTypes(Class.class, JfireSEImpl.class, List.class);
|
||||
constructorModel.setParamNames("clazz", "jfireSE", "list");
|
||||
StringBuilder constructorBody = new StringBuilder();
|
||||
try
|
||||
{
|
||||
each.write(byteArray, instance);
|
||||
MethodModel writeMethod = new MethodModel(Serializer.class.getDeclaredMethod("writeBytes", ByteArray.class, Object.class), classModel);
|
||||
writeMethod.setParamterNames("byteArray", "instance");
|
||||
StringBuilder writeBody = new StringBuilder();
|
||||
MethodModel readMethod = new MethodModel(Serializer.class.getDeclaredMethod("read", ByteArray.class, Object.class), classModel);
|
||||
readMethod.setParamterNames("byteArray", "instance");
|
||||
StringBuilder readBody = new StringBuilder();
|
||||
int fieldIndex = 0;
|
||||
for (FieldInfo fieldInfo : parse)
|
||||
{
|
||||
long l = UNSAFE.objectFieldOffset(fieldInfo.field);
|
||||
if (fieldInfo instanceof PrimitiveFieldInfo primitiveFieldInfo)
|
||||
{
|
||||
switch (fieldInfo.classId)
|
||||
{
|
||||
case ReflectUtil.PRIMITIVE_BYTE ->
|
||||
{
|
||||
writeBody.append("byteArray.put(UNSAFE.getByte(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putByte(instance," + l + ", byteArray.get());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_INT ->
|
||||
{
|
||||
writeBody.append("byteArray.writeVarInt(UNSAFE.getInt(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putInt(instance," + l + ", byteArray.readVarInt());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_SHORT ->
|
||||
{
|
||||
writeBody.append("byteArray.writeVarInt(UNSAFE.getShort(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putShort(instance," + l + ", (short) byteArray.readVarInt());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_LONG ->
|
||||
{
|
||||
writeBody.append("byteArray.writeVarLong(UNSAFE.getLong(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putLong(instance," + l + ", byteArray.readVarLong());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_FLOAT ->
|
||||
{
|
||||
writeBody.append("byteArray.writeFloat(UNSAFE.getFloat(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putFloat(instance," + l + ", byteArray.readFloat());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_DOUBLE ->
|
||||
{
|
||||
writeBody.append("byteArray.writeDouble(UNSAFE.getDouble(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putDouble(instance," + l + ", byteArray.readDouble());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_BOOL ->
|
||||
{
|
||||
writeBody.append("byteArray.writeBoolean(UNSAFE.getBoolean(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putBoolean(instance," + l + ", byteArray.readBoolean());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_CHAR ->
|
||||
{
|
||||
writeBody.append("byteArray.writeChar(UNSAFE.getChar(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putChar(instance," + l + ", byteArray.readChar());\r\n");
|
||||
}
|
||||
default -> throw new RuntimeException("不支持的类型");
|
||||
}
|
||||
}
|
||||
else if (fieldInfo instanceof BoxedFieldInfo boxedFieldInfo)
|
||||
{
|
||||
switch (fieldInfo.classId)
|
||||
{
|
||||
case ReflectUtil.PRIMITIVE_BYTE ->
|
||||
{
|
||||
writeBody.append("byteArray.writeByte((Byte) UNSAFE.getObject(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putObject(instance," + l + ", byteArray.readByte());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_INT ->
|
||||
{
|
||||
writeBody.append("byteArray.writeVarInt((Integer) UNSAFE.getObject(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putObject(instance," + l + ", byteArray.readVarInt());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_SHORT ->
|
||||
{
|
||||
writeBody.append("byteArray.writeVarInt((Short) UNSAFE.getObject(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putObject(instance," + l + ", (short) byteArray.readVarInt());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_LONG ->
|
||||
{
|
||||
writeBody.append("byteArray.writeVarLong((Long) UNSAFE.getObject(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putObject(instance," + l + ", byteArray.readVarLong());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_FLOAT ->
|
||||
{
|
||||
writeBody.append("byteArray.writeFloat((Float) UNSAFE.getObject(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putObject(instance," + l + ", byteArray.readFloat());");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_DOUBLE ->
|
||||
{
|
||||
writeBody.append("byteArray.writeDouble((Double) UNSAFE.getObject(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putObject(instance," + l + ", byteArray.readDouble());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_BOOL ->
|
||||
{
|
||||
writeBody.append("byteArray.writeBoolean((Boolean) UNSAFE.getObject(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putObject(instance," + l + ", byteArray.readBoolean());\r\n");
|
||||
}
|
||||
case ReflectUtil.PRIMITIVE_CHAR ->
|
||||
{
|
||||
writeBody.append("byteArray.writeChar((Character) UNSAFE.getObject(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putObject(instance," + l + ", byteArray.readChar());\r\n");
|
||||
}
|
||||
case ReflectUtil.CLASS_STRING ->
|
||||
{
|
||||
writeBody.append("byteArray.writeString((String) UNSAFE.getObject(instance, " + l + "));\r\n");
|
||||
readBody.append("UNSAFE.putObject(instance," + l + ", byteArray.readString());\r\n");
|
||||
}
|
||||
default -> throw new RuntimeException("不支持的类型");
|
||||
}
|
||||
}
|
||||
else if (fieldInfo instanceof VariableFieldInfo || fieldInfo instanceof FinalFieldInfo)
|
||||
{
|
||||
FieldModel fieldModel = new FieldModel("fieldInfo_$_" + fieldIndex, VariableFieldInfo.class, classModel);
|
||||
classModel.addField(fieldModel);
|
||||
constructorBody.append("fieldInfo_$_" + fieldIndex + "=(FieldInfo)list.get(" + fieldIndex + ");\r\n");
|
||||
writeBody.append("fieldInfo_$_" + fieldIndex + ".write(byteArray,instance);\r\n");
|
||||
readBody.append("fieldInfo_$_" + fieldIndex + ".read(byteArray,instance);\r\n");
|
||||
}
|
||||
fieldIndex++;
|
||||
}
|
||||
constructorModel.setBody(constructorBody.toString());
|
||||
classModel.addConstructor(constructorModel);
|
||||
writeMethod.setBody(writeBody.toString());
|
||||
readMethod.setBody(readBody.toString());
|
||||
classModel.putMethodModel(writeMethod);
|
||||
classModel.putMethodModel(readMethod);
|
||||
CompileHelper compiler = new CompileHelper(Thread.currentThread().getContextClassLoader());
|
||||
Class<?> compile = compiler.compile(classModel);
|
||||
Serializer compiledObjectSerializer = (Serializer) compile.getDeclaredConstructor(Class.class, JfireSEImpl.class, List.class).newInstance(clazz, jfireSE, parse);
|
||||
return compiledObjectSerializer;
|
||||
}
|
||||
catch (NoSuchMethodException | IOException | ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
@ -10,7 +9,7 @@ public class PrimitiveFieldInfo extends FieldInfo
|
|||
{
|
||||
public PrimitiveFieldInfo(Field field)
|
||||
{
|
||||
super(ReflectUtil.getClassId(field.getType()), new ValueAccessor(field));
|
||||
super(field);
|
||||
}
|
||||
|
||||
public void write(ByteArray byteArray, Object instance)
|
||||
|
@ -28,4 +27,21 @@ public class PrimitiveFieldInfo extends FieldInfo
|
|||
default -> throw new RuntimeException("不支持的类型");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteArray byteArray, Object instance)
|
||||
{
|
||||
switch (classId)
|
||||
{
|
||||
case ReflectUtil.PRIMITIVE_BYTE -> accessor.set(instance, byteArray.get());
|
||||
case ReflectUtil.PRIMITIVE_INT -> accessor.set(instance, byteArray.readVarInt());
|
||||
case ReflectUtil.PRIMITIVE_SHORT -> accessor.set(instance, (short) 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.readBoolean());
|
||||
case ReflectUtil.PRIMITIVE_CHAR -> accessor.set(instance, byteArray.readChar());
|
||||
default -> throw new RuntimeException("不支持的类型");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import com.jfirer.se2.JfireSEImpl;
|
||||
|
@ -17,7 +15,7 @@ public class VariableFieldInfo extends FieldInfo
|
|||
|
||||
public VariableFieldInfo(Field field, JfireSEImpl jfireSE)
|
||||
{
|
||||
super(ReflectUtil.getClassId(field.getType()), new ValueAccessor(field));
|
||||
super(field);
|
||||
classInfo = jfireSE.getForSerialize(field.getType());
|
||||
this.jfireSE = jfireSE;
|
||||
if (field.getType().isInterface())
|
||||
|
@ -66,4 +64,75 @@ public class VariableFieldInfo extends FieldInfo
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteArray byteArray, Object instance)
|
||||
{
|
||||
byte flag = byteArray.get();
|
||||
if (flag == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
case JfireSE.NAME_ID_CONTENT_TRACK ->
|
||||
{
|
||||
byte[] classNameBytes = byteArray.readBytesWithSizeEmbedded();
|
||||
int classId = byteArray.readVarInt();
|
||||
classInfo = jfireSE.getForDeSerialize(classNameBytes, classId);
|
||||
Object property = classInfo.readWithTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.NAME_ID_CONTENT_UN_TRACK ->
|
||||
{
|
||||
byte[] classNameBytes = byteArray.readBytesWithSizeEmbedded();
|
||||
int classId = byteArray.readVarInt();
|
||||
classInfo = jfireSE.getForDeSerialize(classNameBytes, classId);
|
||||
Object property = classInfo.readWithoutTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.ID_INSTANCE_ID ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
int instanceId = byteArray.readVarInt();
|
||||
classInfo = jfireSE.getForDeSerialize(classId);
|
||||
Object proeprty = classInfo.getInstanceById(instanceId);
|
||||
accessor.setObject(instance, proeprty);
|
||||
}
|
||||
case JfireSE.id_content_track ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
classInfo = jfireSE.getForDeSerialize(classId);
|
||||
Object property = classInfo.readWithTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.id_content_un_track ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
classInfo = jfireSE.getForDeSerialize(classId);
|
||||
Object property = classInfo.readWithoutTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.instance_id ->
|
||||
{
|
||||
int instanceId = byteArray.readVarInt();
|
||||
Object property = firstClassInfo.getInstanceById(instanceId);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.content_track ->
|
||||
{
|
||||
Object property = firstClassInfo.readWithTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.content_un_track ->
|
||||
{
|
||||
Object property = firstClassInfo.readWithoutTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
default -> throw new RuntimeException("flag:" + flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import org.openjdk.jmh.runner.options.OptionsBuilder;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@Warmup(iterations = 2, time = 1)
|
||||
@Warmup(iterations = 2, time = 3)
|
||||
@Measurement(iterations = 3, time = 3)
|
||||
@OutputTimeUnit(TimeUnit.SECONDS)
|
||||
@Fork(1)
|
||||
|
@ -28,7 +28,7 @@ public class BenchMark
|
|||
Fury fury = Fury.builder().withLanguage(Language.JAVA)//
|
||||
.requireClassRegistration(false)//
|
||||
.withRefTracking(true).build();
|
||||
JfireSE jfireSE = JfireSE.build();
|
||||
JfireSE jfireSE = JfireSE.supportRefTracking(true).build();
|
||||
|
||||
@Benchmark
|
||||
public void testNoCompile()
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package org.example;
|
||||
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import io.fury.Fury;
|
||||
import io.fury.config.Language;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FunctionTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
|
@ -20,4 +22,26 @@ public class FunctionTest
|
|||
Assert.assertEquals(20, byteArray.readVarInt());
|
||||
Assert.assertEquals(13453242, byteArray.readVarLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2()
|
||||
{
|
||||
TestData testData = new TestData();
|
||||
testData.setB(true);
|
||||
JfireSE jfireSE = JfireSE.build();
|
||||
byte[] bytes = jfireSE.write(testData);
|
||||
Assert.assertEquals(testData, jfireSE.read(bytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3()
|
||||
{
|
||||
Fury fury = Fury.builder().withLanguage(Language.JAVA)//
|
||||
.requireClassRegistration(false)//
|
||||
.withRefTracking(true).build();
|
||||
TestData data = new TestData();
|
||||
byte[] serialize = fury.serialize(data);
|
||||
byte[] serialize1 = fury.serialize(data);
|
||||
Assert.assertArrayEquals(serialize, serialize1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,20 +2,18 @@ package org.example;
|
|||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class TestData implements Serializable
|
||||
public class TestData
|
||||
{
|
||||
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 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'};
|
||||
|
@ -26,88 +24,5 @@ public class TestData implements Serializable
|
|||
// 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