Update generators
This commit is contained in:
parent
2bf847224a
commit
784c86456c
@ -41,4 +41,8 @@ public sealed interface ComputedType permits VersionedComputedType, ComputedType
|
||||
*/
|
||||
Stream<ComputedType> getDependents();
|
||||
|
||||
default boolean isPrimitive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,7 @@
|
||||
package it.cavallium.data.generator.plugin;
|
||||
|
||||
import static it.cavallium.data.generator.plugin.DataModel.joinPackage;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import it.cavallium.data.generator.nativedata.Serializers;
|
||||
import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Objects;
|
||||
@ -101,7 +98,7 @@ public final class ComputedTypeBase implements VersionedComputedType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeName getJTypeName(String basePackageName) {
|
||||
public ClassName getJTypeName(String basePackageName) {
|
||||
return ClassName.get(getVersion().getDataPackage(basePackageName), type.type());
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
package it.cavallium.data.generator.plugin;
|
||||
|
||||
import static it.cavallium.data.generator.plugin.DataModel.joinPackage;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import it.cavallium.data.generator.nativedata.Int52Serializer;
|
||||
@ -9,16 +7,21 @@ import it.cavallium.data.generator.nativedata.Serializers;
|
||||
import it.cavallium.data.generator.nativedata.StringSerializer;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class ComputedTypeNative implements ComputedType {
|
||||
|
||||
private static final Set<String> PRIMITIVE_TYPES = Set.of("boolean", "short", "char", "int", "long", "float", "double", "byte");
|
||||
|
||||
private final String type;
|
||||
private final ComputedTypeSupplier computedTypeSupplier;
|
||||
private boolean primitive;
|
||||
|
||||
public ComputedTypeNative(String type, ComputedTypeSupplier computedTypeSupplier) {
|
||||
this.type = type;
|
||||
this.computedTypeSupplier = computedTypeSupplier;
|
||||
this.primitive = PRIMITIVE_TYPES.contains(type);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@ -109,4 +112,8 @@ public final class ComputedTypeNative implements ComputedType {
|
||||
public String toString() {
|
||||
return type + " (native)";
|
||||
}
|
||||
|
||||
public boolean isPrimitive() {
|
||||
return primitive;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package it.cavallium.data.generator.plugin;
|
||||
|
||||
import static it.cavallium.data.generator.plugin.DataModel.joinPackage;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType;
|
||||
@ -94,7 +92,7 @@ public final class ComputedTypeSuper implements VersionedComputedType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeName getJTypeName(String basePackageName) {
|
||||
public ClassName getJTypeName(String basePackageName) {
|
||||
return ClassName.get(getVersion().getDataPackage(basePackageName), type.type());
|
||||
}
|
||||
|
||||
|
@ -672,6 +672,16 @@ public class DataModel {
|
||||
.filter(t -> t instanceof ComputedTypeBase).map(t -> (ComputedTypeBase) t);
|
||||
}
|
||||
|
||||
public Stream<ComputedTypeArray> getArrayTypesComputed(ComputedVersion version) {
|
||||
return this.computedTypes.get(version.getVersion()).values().stream()
|
||||
.filter(t -> t instanceof ComputedTypeArray).map(t -> (ComputedTypeArray) t);
|
||||
}
|
||||
|
||||
public Stream<ComputedTypeNullable> getNullableTypesComputed(ComputedVersion version) {
|
||||
return this.computedTypes.get(version.getVersion()).values().stream()
|
||||
.filter(t -> t instanceof ComputedTypeNullable).map(t -> (ComputedTypeNullable) t);
|
||||
}
|
||||
|
||||
public Optional<ComputedVersion> getNextVersion(ComputedVersion versionConfiguration) {
|
||||
var nextVersion = versions.get(versionConfiguration.getVersion() + 1);
|
||||
return Optional.ofNullable(nextVersion);
|
||||
@ -743,7 +753,7 @@ public class DataModel {
|
||||
if (prevVersion != null) {
|
||||
return versions.get(prevVersion.getVersion().getVersion() + 1);
|
||||
} else {
|
||||
return type.getVersion();
|
||||
return versions.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -800,8 +810,29 @@ public class DataModel {
|
||||
}
|
||||
}
|
||||
|
||||
public Stream<ComputedTypeSuper> getSuperTypesOf(VersionedComputedType baseType) {
|
||||
return getSuperTypesComputed(baseType.getVersion()).filter(type -> type.subTypes().contains(baseType));
|
||||
/**
|
||||
* @param includeMulti Includes all used super type versions
|
||||
*/
|
||||
public Stream<ComputedTypeSuper> getSuperTypesOf(VersionedComputedType baseType, boolean includeMulti) {
|
||||
ComputedVersion lowestBaseVersion = getTypeFirstSameVersion(baseType);
|
||||
if (lowestBaseVersion == null) {
|
||||
return Stream.of();
|
||||
}
|
||||
return getSuperTypesComputed(baseType.getVersion())
|
||||
.filter(type -> type.subTypes().contains(baseType))
|
||||
.mapMulti((superType, cons) -> {
|
||||
if (includeMulti) {
|
||||
while (superType != null) {
|
||||
ComputedVersion lowestSuperVersion = Objects.requireNonNull(getTypeFirstSameVersion(superType));
|
||||
if (lowestSuperVersion.compareTo(lowestBaseVersion) >= 0) {
|
||||
cons.accept(superType);
|
||||
}
|
||||
superType = getPrevVersion(superType);
|
||||
}
|
||||
} else {
|
||||
cons.accept(superType);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Stream<ComputedTypeSuper> getExtendsInterfaces(ComputedTypeSuper superType) {
|
||||
|
@ -24,6 +24,10 @@ import it.cavallium.data.generator.plugin.classgen.GenINullableSuperType;
|
||||
import it.cavallium.data.generator.plugin.classgen.GenIType;
|
||||
import it.cavallium.data.generator.plugin.classgen.GenIVersion;
|
||||
import it.cavallium.data.generator.plugin.classgen.GenNullableX;
|
||||
import it.cavallium.data.generator.plugin.classgen.GenSerializerArrayX;
|
||||
import it.cavallium.data.generator.plugin.classgen.GenSerializerBaseX;
|
||||
import it.cavallium.data.generator.plugin.classgen.GenSerializerNullableX;
|
||||
import it.cavallium.data.generator.plugin.classgen.GenSerializerSuperX;
|
||||
import it.cavallium.data.generator.plugin.classgen.GenSuperType;
|
||||
import it.cavallium.data.generator.plugin.classgen.GenVersion;
|
||||
import it.cavallium.data.generator.plugin.classgen.GenVersions;
|
||||
@ -175,6 +179,14 @@ public class SourcesGenerator {
|
||||
|
||||
new GenDataSuperX(genParams).run();
|
||||
|
||||
new GenSerializerSuperX(genParams).run();
|
||||
|
||||
new GenSerializerBaseX(genParams).run();
|
||||
|
||||
new GenSerializerArrayX(genParams).run();
|
||||
|
||||
new GenSerializerNullableX(genParams).run();
|
||||
|
||||
// Update the hash at the end
|
||||
Files.writeString(hashPath, basePackageName + '\n' + useRecordBuilders + '\n' + curHash + '\n',
|
||||
StandardCharsets.UTF_8, TRUNCATE_EXISTING, WRITE, CREATE);
|
||||
|
@ -156,7 +156,7 @@ public class GenCurrentVersion extends ClassGenerator {
|
||||
.addStatement(
|
||||
"data = " + versionConfiguration.getPackage(basePackageName)
|
||||
+ ".Version.upgradeToNextVersion(($T) data)",
|
||||
ClassName.get(versionConfiguration.getDataPackage(basePackageName), "IBaseType")
|
||||
ClassName.get(versionConfiguration.getPackage(basePackageName), "IBaseType")
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -178,7 +178,7 @@ public class GenCurrentVersion extends ClassGenerator {
|
||||
var baseTypeClassName = ClassName.get(dataModel.getRootPackage(basePackageName), "BaseType");
|
||||
methodBuilder.addParameter(baseTypeClassName, "type");
|
||||
|
||||
var iBaseTypeClassName = ClassName.get(version.getDataPackage(basePackageName), "IBaseType");
|
||||
var iBaseTypeClassName = ClassName.get(version.getPackage(basePackageName), "IBaseType");
|
||||
methodBuilder.returns(ParameterizedTypeName.get(ClassName.get(Class.class), WildcardTypeName.subtypeOf(iBaseTypeClassName)));
|
||||
|
||||
methodBuilder.beginControlFlow("return switch (type)");
|
||||
|
@ -38,12 +38,17 @@ public class GenDataBaseX extends ClassGenerator {
|
||||
classBuilder.addModifiers(Modifier.PUBLIC);
|
||||
|
||||
var baseTypeClass = ClassName.get(dataModel.getRootPackage(basePackageName), "BaseType");
|
||||
var iTypeClass = ClassName.get(version.getPackage(basePackageName), "IBaseType");
|
||||
|
||||
dataModel.getTypeSameVersions(base).forEach(v -> {
|
||||
var iTypeClass = ClassName.get(v.getPackage(basePackageName), "IBaseType");
|
||||
classBuilder.addSuperinterface(iTypeClass);
|
||||
});
|
||||
|
||||
dataModel.getSuperTypesOf(base).forEach(superType -> {
|
||||
dataModel.getSuperTypesOf(base, true).forEach(superType -> {
|
||||
classBuilder.addSuperinterface(superType.getJTypeName(basePackageName));
|
||||
});
|
||||
|
||||
dataModel.getSuperTypesOf(base, false).forEach(superType -> {
|
||||
classBuilder.addMethod(MethodSpec
|
||||
.methodBuilder("getMetaId$" + superType.getName())
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
||||
|
@ -36,9 +36,10 @@ public class GenDataSuperX extends ClassGenerator {
|
||||
|
||||
classBuilder.addModifiers(Modifier.PUBLIC);
|
||||
|
||||
var baseTypeClass = ClassName.get(dataModel.getRootPackage(basePackageName), "BaseType");
|
||||
var iBaseTypeClass = ClassName.get(version.getPackage(basePackageName), "IBaseType");
|
||||
classBuilder.addSuperinterface(iBaseTypeClass);
|
||||
dataModel.getTypeSameVersions(typeSuper).forEach(v -> {
|
||||
var iTypeClass = ClassName.get(v.getPackage(basePackageName), "IBaseType");
|
||||
classBuilder.addSuperinterface(iTypeClass);
|
||||
});
|
||||
|
||||
dataModel.getExtendsInterfaces(typeSuper).forEach(superType -> {
|
||||
classBuilder.addSuperinterface(superType.getJTypeName(basePackageName));
|
||||
@ -70,7 +71,7 @@ public class GenDataSuperX extends ClassGenerator {
|
||||
classBuilder.addMethod(setter.build());
|
||||
});
|
||||
|
||||
dataModel.getSuperTypesOf(typeSuper).forEach(superType -> {
|
||||
dataModel.getSuperTypesOf(typeSuper, true).forEach(superType -> {
|
||||
classBuilder.addSuperinterface(superType.getJTypeName(basePackageName));
|
||||
});
|
||||
|
||||
|
@ -7,10 +7,8 @@ import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeVariableName;
|
||||
import com.squareup.javapoet.WildcardTypeName;
|
||||
import it.cavallium.data.generator.DataSerializer;
|
||||
import it.cavallium.data.generator.plugin.ClassGenerator;
|
||||
import it.cavallium.data.generator.plugin.ClassGenerator.ClassGeneratorParams;
|
||||
import java.io.IOException;
|
||||
import java.util.stream.Stream;
|
||||
import javax.lang.model.element.Modifier;
|
||||
@ -27,21 +25,6 @@ public class GenIVersion extends ClassGenerator {
|
||||
iVersionClass.addModifiers(Modifier.PUBLIC);
|
||||
iVersionClass.addTypeVariable(TypeVariableName.get("B"));
|
||||
|
||||
// Add getClass method
|
||||
{
|
||||
var getClassMethodBuilder = MethodSpec
|
||||
.methodBuilder("getClass")
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addModifiers(Modifier.ABSTRACT)
|
||||
.returns(ParameterizedTypeName.get(ClassName.get(Class.class),
|
||||
WildcardTypeName.subtypeOf(TypeVariableName.get("B"))
|
||||
))
|
||||
.addParameter(ParameterSpec
|
||||
.builder(ClassName.get(dataModel.getRootPackage(basePackageName), "BaseType"), "type")
|
||||
.build());
|
||||
iVersionClass.addMethod(getClassMethodBuilder.build());
|
||||
}
|
||||
|
||||
// Add getSerializer method
|
||||
{
|
||||
var getSerializerMethodBuilder = MethodSpec
|
||||
|
@ -0,0 +1,119 @@
|
||||
package it.cavallium.data.generator.plugin.classgen;
|
||||
|
||||
import com.squareup.javapoet.ArrayTypeName;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeSpec.Builder;
|
||||
import it.cavallium.data.generator.DataSerializer;
|
||||
import it.cavallium.data.generator.nativedata.ImmutableWrappedArrayList;
|
||||
import it.cavallium.data.generator.plugin.ClassGenerator;
|
||||
import it.cavallium.data.generator.plugin.ComputedTypeArrayVersioned;
|
||||
import it.cavallium.data.generator.plugin.ComputedVersion;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class GenSerializerArrayX extends ClassGenerator {
|
||||
|
||||
public GenSerializerArrayX(ClassGeneratorParams params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<GeneratedClass> generateClasses() {
|
||||
return dataModel.getVersionsSet().parallelStream().flatMap(this::generateVersionClasses);
|
||||
}
|
||||
|
||||
private Stream<GeneratedClass> generateVersionClasses(ComputedVersion version) {
|
||||
return dataModel
|
||||
.getArrayTypesComputed(version)
|
||||
.filter(type -> type instanceof ComputedTypeArrayVersioned versioned && versioned.getVersion().equals(version))
|
||||
.map(type -> generateTypeVersioned(version, (ComputedTypeArrayVersioned) type));
|
||||
}
|
||||
|
||||
private GeneratedClass generateTypeVersioned(ComputedVersion version, ComputedTypeArrayVersioned typeArray) {
|
||||
ClassName serializerClassName = typeArray.getJSerializerName(basePackageName);
|
||||
var typeArrayClassName = typeArray.getJTypeName(basePackageName);
|
||||
|
||||
var classBuilder = TypeSpec.classBuilder(serializerClassName.simpleName());
|
||||
|
||||
classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
|
||||
classBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(DataSerializer.class), typeArrayClassName));
|
||||
|
||||
generateSerialize(version, typeArray, classBuilder);
|
||||
|
||||
generateDeserialize(version, typeArray, classBuilder);
|
||||
|
||||
return new GeneratedClass(serializerClassName.packageName(), classBuilder);
|
||||
}
|
||||
|
||||
private void generateSerialize(ComputedVersion version, ComputedTypeArrayVersioned typeArray, Builder classBuilder) {
|
||||
var method = MethodSpec.methodBuilder("serialize");
|
||||
|
||||
method.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
method.addException(IOException.class);
|
||||
|
||||
method.addParameter(ParameterSpec.builder(DataOutput.class, "out").build());
|
||||
method.addParameter(ParameterSpec
|
||||
.builder(typeArray.getJTypeName(basePackageName), "data")
|
||||
.addAnnotation(NotNull.class)
|
||||
.build());
|
||||
|
||||
if (version.isCurrent()) {
|
||||
method.addStatement("$T.requireNonNull(data)", Objects.class);
|
||||
method.addCode("\n");
|
||||
method.addStatement("final int sz = data.size()");
|
||||
method.addStatement("out.writeInt(sz)");
|
||||
method.addCode("\n");
|
||||
method.beginControlFlow("for (int i = 0; i < sz; ++i)");
|
||||
var baseSerializerInstance = typeArray.getBase().getJSerializerInstance(basePackageName);
|
||||
method.addStatement("$T.$N.serialize(out, ($T) data.get(i))",
|
||||
baseSerializerInstance.className(),
|
||||
baseSerializerInstance.fieldName(),
|
||||
typeArray.getBase().getJTypeName(basePackageName)
|
||||
);
|
||||
method.endControlFlow();
|
||||
} else {
|
||||
method.addStatement("throw new $T()", NotSerializableException.class);
|
||||
}
|
||||
|
||||
classBuilder.addMethod(method.build());
|
||||
}
|
||||
|
||||
private void generateDeserialize(ComputedVersion version, ComputedTypeArrayVersioned typeArray, Builder classBuilder) {
|
||||
var method = MethodSpec.methodBuilder("deserialize");
|
||||
|
||||
method.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
method.addException(IOException.class);
|
||||
|
||||
var typeArrayClassName = typeArray.getJTypeName(basePackageName);
|
||||
method.returns(typeArrayClassName);
|
||||
method.addAnnotation(NotNull.class);
|
||||
|
||||
method.addParameter(ParameterSpec.builder(DataInput.class, "in").build());
|
||||
|
||||
method.addStatement("int sz = in.readInt()");
|
||||
var arrayTypeName = ArrayTypeName.of(typeArray.getBase().getJTypeName(basePackageName));
|
||||
method.addStatement("$T a = new $T[sz]", arrayTypeName, arrayTypeName.componentType);
|
||||
method.addCode("\n");
|
||||
method.beginControlFlow("for (int i = 0; i < sz; ++i)");
|
||||
var baseSerializerInstance = typeArray.getBase().getJSerializerInstance(basePackageName);
|
||||
method.addStatement("a[i] = $T.$N.deserialize(in)", baseSerializerInstance.className(), baseSerializerInstance.fieldName());
|
||||
method.endControlFlow();
|
||||
|
||||
method.addCode("\n");
|
||||
method.addStatement("return new $T(a)", ParameterizedTypeName.get(ClassName.get(ImmutableWrappedArrayList.class),
|
||||
typeArray.getBase().getJTypeName(basePackageName)));
|
||||
|
||||
classBuilder.addMethod(method.build());
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
package it.cavallium.data.generator.plugin.classgen;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.CodeBlock;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeSpec.Builder;
|
||||
import it.cavallium.data.generator.DataSerializer;
|
||||
import it.cavallium.data.generator.plugin.ClassGenerator;
|
||||
import it.cavallium.data.generator.plugin.ComputedTypeBase;
|
||||
import it.cavallium.data.generator.plugin.ComputedVersion;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class GenSerializerBaseX extends ClassGenerator {
|
||||
|
||||
public GenSerializerBaseX(ClassGeneratorParams params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<GeneratedClass> generateClasses() {
|
||||
return dataModel.getVersionsSet().parallelStream().flatMap(this::generateVersionClasses);
|
||||
}
|
||||
|
||||
private Stream<GeneratedClass> generateVersionClasses(ComputedVersion version) {
|
||||
return dataModel
|
||||
.getBaseTypesComputed(version)
|
||||
.filter(type -> type.getVersion().equals(version))
|
||||
.map(type -> generateTypeVersioned(version, type));
|
||||
}
|
||||
|
||||
private GeneratedClass generateTypeVersioned(ComputedVersion version, ComputedTypeBase typeBase) {
|
||||
ClassName serializerClassName = typeBase.getJSerializerName(basePackageName);
|
||||
ClassName typeBaseClassName = typeBase.getJTypeName(basePackageName);
|
||||
|
||||
var classBuilder = TypeSpec.classBuilder(serializerClassName.simpleName());
|
||||
|
||||
classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
|
||||
classBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(DataSerializer.class), typeBaseClassName));
|
||||
|
||||
generateSerialize(version, typeBase, classBuilder);
|
||||
|
||||
generateDeserialize(version, typeBase, classBuilder);
|
||||
|
||||
return new GeneratedClass(serializerClassName.packageName(), classBuilder);
|
||||
}
|
||||
|
||||
private void generateSerialize(ComputedVersion version, ComputedTypeBase typeBase, Builder classBuilder) {
|
||||
var method = MethodSpec.methodBuilder("serialize");
|
||||
|
||||
method.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
method.addException(IOException.class);
|
||||
|
||||
method.addParameter(ParameterSpec.builder(DataOutput.class, "out").build());
|
||||
method.addParameter(ParameterSpec
|
||||
.builder(typeBase.getJTypeName(basePackageName), "data")
|
||||
.addAnnotation(NotNull.class)
|
||||
.build());
|
||||
|
||||
if (version.isCurrent()) {
|
||||
method.addStatement("$T.requireNonNull(data)", Objects.class);
|
||||
method.addCode("\n");
|
||||
|
||||
typeBase.getData().forEach((fieldName, fieldType) -> {
|
||||
if (fieldType.isPrimitive()) {
|
||||
method.addStatement("out.write$N(data.$N())", StringUtils.capitalize(fieldType.getName()), fieldName);
|
||||
} else {
|
||||
var serializerInstance = fieldType.getJSerializerInstance(basePackageName);
|
||||
method.addStatement("$T.$N.serialize(out, data.$N())",
|
||||
serializerInstance.className(),
|
||||
serializerInstance.fieldName(),
|
||||
fieldName
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
method.addStatement("throw new $T()", NotSerializableException.class);
|
||||
}
|
||||
|
||||
classBuilder.addMethod(method.build());
|
||||
}
|
||||
|
||||
private void generateDeserialize(ComputedVersion version, ComputedTypeBase typeBase, Builder classBuilder) {
|
||||
var method = MethodSpec.methodBuilder("deserialize");
|
||||
|
||||
method.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
method.addException(IOException.class);
|
||||
|
||||
ClassName typeBaseClassName = typeBase.getJTypeName(basePackageName);
|
||||
method.returns(typeBaseClassName);
|
||||
method.addAnnotation(NotNull.class);
|
||||
|
||||
method.addParameter(ParameterSpec.builder(DataInput.class, "in").build());
|
||||
|
||||
method.addCode("return new $T(\n$>", typeBaseClassName);
|
||||
typeBase.getData().entrySet().stream().flatMap(entry -> {
|
||||
var fieldType = entry.getValue();
|
||||
if (fieldType.isPrimitive()) {
|
||||
return Stream.of(CodeBlock.of(",\n"), CodeBlock.of("in.read$N()", StringUtils.capitalize(fieldType.getName())));
|
||||
} else {
|
||||
var serializerInstance = fieldType.getJSerializerInstance(basePackageName);
|
||||
return Stream.of(CodeBlock.of(",\n"), CodeBlock.of("$T.$N.deserialize(in)",
|
||||
serializerInstance.className(),
|
||||
serializerInstance.fieldName()
|
||||
));
|
||||
}
|
||||
}).skip(1).forEach(method::addCode);
|
||||
method.addCode("$<\n");
|
||||
method.addStatement(")");
|
||||
|
||||
classBuilder.addMethod(method.build());
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package it.cavallium.data.generator.plugin.classgen;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeSpec.Builder;
|
||||
import it.cavallium.data.generator.DataSerializer;
|
||||
import it.cavallium.data.generator.plugin.ClassGenerator;
|
||||
import it.cavallium.data.generator.plugin.ComputedTypeNullableVersioned;
|
||||
import it.cavallium.data.generator.plugin.ComputedVersion;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class GenSerializerNullableX extends ClassGenerator {
|
||||
|
||||
public GenSerializerNullableX(ClassGeneratorParams params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<GeneratedClass> generateClasses() {
|
||||
return dataModel.getVersionsSet().parallelStream().flatMap(this::generateVersionClasses);
|
||||
}
|
||||
|
||||
private Stream<GeneratedClass> generateVersionClasses(ComputedVersion version) {
|
||||
return dataModel
|
||||
.getNullableTypesComputed(version)
|
||||
.filter(type -> type instanceof ComputedTypeNullableVersioned versioned && versioned.getVersion().equals(version))
|
||||
.map(type -> generateTypeVersioned(version, (ComputedTypeNullableVersioned) type));
|
||||
}
|
||||
|
||||
private GeneratedClass generateTypeVersioned(ComputedVersion version, ComputedTypeNullableVersioned typeNullable) {
|
||||
ClassName serializerClassName = typeNullable.getJSerializerName(basePackageName);
|
||||
var typeNullableClassName = typeNullable.getJTypeName(basePackageName);
|
||||
|
||||
var classBuilder = TypeSpec.classBuilder(serializerClassName.simpleName());
|
||||
|
||||
classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
|
||||
classBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(DataSerializer.class), typeNullableClassName));
|
||||
|
||||
generateSerialize(version, typeNullable, classBuilder);
|
||||
|
||||
generateDeserialize(version, typeNullable, classBuilder);
|
||||
|
||||
return new GeneratedClass(serializerClassName.packageName(), classBuilder);
|
||||
}
|
||||
|
||||
private void generateSerialize(ComputedVersion version, ComputedTypeNullableVersioned typeNullable, Builder classBuilder) {
|
||||
var method = MethodSpec.methodBuilder("serialize");
|
||||
|
||||
var base = typeNullable.getBase();
|
||||
var baseTypeName = base.getJTypeName(basePackageName);
|
||||
var baseSerializerInstance = base.getJSerializerInstance(basePackageName);
|
||||
|
||||
method.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
method.addException(IOException.class);
|
||||
|
||||
method.addParameter(ParameterSpec.builder(DataOutput.class, "out").build());
|
||||
method.addParameter(ParameterSpec
|
||||
.builder(typeNullable.getJTypeName(basePackageName), "data")
|
||||
.addAnnotation(NotNull.class)
|
||||
.build());
|
||||
|
||||
if (version.isCurrent()) {
|
||||
method.addStatement("$T.requireNonNull(data)", Objects.class);
|
||||
method.addCode("\n");
|
||||
method.addStatement("boolean notEmpty = !data.isEmpty()");
|
||||
method.addStatement("out.writeBoolean(notEmpty)");
|
||||
method.beginControlFlow("if (notEmpty)");
|
||||
method.addStatement("$T.$N.serialize(out, ($T) data.getNullable())",
|
||||
baseSerializerInstance.className(),
|
||||
baseSerializerInstance.fieldName(),
|
||||
baseTypeName
|
||||
);
|
||||
method.endControlFlow();
|
||||
} else {
|
||||
method.addStatement("throw new $T()", NotSerializableException.class);
|
||||
}
|
||||
|
||||
classBuilder.addMethod(method.build());
|
||||
}
|
||||
|
||||
private void generateDeserialize(ComputedVersion version, ComputedTypeNullableVersioned typeNullable, Builder classBuilder) {
|
||||
var method = MethodSpec.methodBuilder("deserialize");
|
||||
|
||||
var base = typeNullable.getBase();
|
||||
var baseTypeName = base.getJTypeName(basePackageName);
|
||||
var baseSerializerInstance = base.getJSerializerInstance(basePackageName);
|
||||
|
||||
method.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
method.addException(IOException.class);
|
||||
|
||||
var typeNullableClassName = typeNullable.getJTypeName(basePackageName);
|
||||
method.returns(typeNullableClassName);
|
||||
method.addAnnotation(NotNull.class);
|
||||
|
||||
method.addParameter(ParameterSpec.builder(DataInput.class, "in").build());
|
||||
|
||||
method.addStatement("return in.readBoolean() ? new $T(($T) $T.$N.deserialize(in)) : $T.empty()",
|
||||
typeNullableClassName,
|
||||
baseTypeName,
|
||||
baseSerializerInstance.className(),
|
||||
baseSerializerInstance.fieldName(),
|
||||
typeNullableClassName
|
||||
);
|
||||
|
||||
classBuilder.addMethod(method.build());
|
||||
}
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
package it.cavallium.data.generator.plugin.classgen;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeSpec.Builder;
|
||||
import it.cavallium.data.generator.DataSerializer;
|
||||
import it.cavallium.data.generator.plugin.ClassGenerator;
|
||||
import it.cavallium.data.generator.plugin.ComputedType;
|
||||
import it.cavallium.data.generator.plugin.ComputedTypeSuper;
|
||||
import it.cavallium.data.generator.plugin.ComputedVersion;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class GenSerializerSuperX extends ClassGenerator {
|
||||
|
||||
public GenSerializerSuperX(ClassGeneratorParams params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<GeneratedClass> generateClasses() {
|
||||
return dataModel.getVersionsSet().parallelStream().flatMap(this::generateVersionClasses);
|
||||
}
|
||||
|
||||
private Stream<GeneratedClass> generateVersionClasses(ComputedVersion version) {
|
||||
return dataModel
|
||||
.getSuperTypesComputed(version)
|
||||
.filter(type -> type.getVersion().equals(version))
|
||||
.map(type -> generateTypeVersioned(version, type));
|
||||
}
|
||||
|
||||
private GeneratedClass generateTypeVersioned(ComputedVersion version, ComputedTypeSuper typeSuper) {
|
||||
ClassName serializerClassName = typeSuper.getJSerializerName(basePackageName);
|
||||
ClassName typeSuperClassName = typeSuper.getJTypeName(basePackageName);
|
||||
|
||||
var classBuilder = TypeSpec.classBuilder(serializerClassName.simpleName());
|
||||
|
||||
classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
|
||||
classBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(DataSerializer.class), typeSuperClassName));
|
||||
|
||||
generateCheckIdValidity(version, typeSuper, classBuilder);
|
||||
|
||||
generateSerialize(version, typeSuper, classBuilder);
|
||||
|
||||
generateDeserialize(version, typeSuper, classBuilder);
|
||||
|
||||
return new GeneratedClass(serializerClassName.packageName(), classBuilder);
|
||||
}
|
||||
|
||||
private void generateCheckIdValidity(ComputedVersion version, ComputedTypeSuper typeSuper, Builder classBuilder) {
|
||||
int max = typeSuper.subTypes().size();
|
||||
var method = MethodSpec.methodBuilder("checkIdValidity");
|
||||
method.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);
|
||||
method.addException(IOException.class);
|
||||
method.addParameter(ParameterSpec.builder(int.class, "id").build());
|
||||
|
||||
method.beginControlFlow("if (id < 0 || id >= $L)", max);
|
||||
method.addStatement("throw new $T(new $T(id))", IOException.class, IndexOutOfBoundsException.class);
|
||||
method.endControlFlow();
|
||||
|
||||
classBuilder.addMethod(method.build());
|
||||
}
|
||||
|
||||
private void generateSerialize(ComputedVersion version, ComputedTypeSuper typeSuper, Builder classBuilder) {
|
||||
var method = MethodSpec.methodBuilder("serialize");
|
||||
|
||||
method.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
method.addException(IOException.class);
|
||||
|
||||
method.addParameter(ParameterSpec.builder(DataOutput.class, "out").build());
|
||||
method.addParameter(ParameterSpec
|
||||
.builder(typeSuper.getJTypeName(basePackageName), "data")
|
||||
.addAnnotation(NotNull.class)
|
||||
.build());
|
||||
|
||||
if (version.isCurrent()) {
|
||||
method.addStatement("$T.requireNonNull(data)", Objects.class);
|
||||
method.addStatement("int id = data.getMetaId$$$N()", typeSuper.getName());
|
||||
method.addStatement("out.writeByte(id)");
|
||||
method.beginControlFlow("switch (id)");
|
||||
|
||||
var subTypes = typeSuper.subTypes().toArray(ComputedType[]::new);
|
||||
int max = subTypes.length;
|
||||
for (int i = 0; i < max; i++) {
|
||||
var subType = subTypes[i];
|
||||
var subSerializerInstance = subType.getJSerializerInstance(basePackageName);
|
||||
method.addStatement("case $L -> $T.$N.serialize(out, ($T) data)",
|
||||
i,
|
||||
subSerializerInstance.className(),
|
||||
subSerializerInstance.fieldName(),
|
||||
subType.getJTypeName(basePackageName)
|
||||
);
|
||||
}
|
||||
method.beginControlFlow("default ->");
|
||||
method.addStatement("checkIdValidity(id)");
|
||||
method.addComment("Not reachable:");
|
||||
method.addStatement("throw new $T()", IllegalStateException.class);
|
||||
method.endControlFlow();
|
||||
method.endControlFlow();
|
||||
} else {
|
||||
method.addStatement("throw new $T()", NotSerializableException.class);
|
||||
}
|
||||
|
||||
classBuilder.addMethod(method.build());
|
||||
}
|
||||
|
||||
private void generateDeserialize(ComputedVersion version, ComputedTypeSuper typeSuper, Builder classBuilder) {
|
||||
var method = MethodSpec.methodBuilder("deserialize");
|
||||
|
||||
method.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
method.addException(IOException.class);
|
||||
|
||||
ClassName typeSuperClassName = typeSuper.getJTypeName(basePackageName);
|
||||
method.returns(typeSuperClassName);
|
||||
method.addAnnotation(NotNull.class);
|
||||
|
||||
method.addParameter(ParameterSpec.builder(DataInput.class, "in").build());
|
||||
|
||||
method.addStatement("int id = in.readUnsignedByte()");
|
||||
method.beginControlFlow("return switch (id)");
|
||||
|
||||
var subTypes = typeSuper.subTypes().toArray(ComputedType[]::new);
|
||||
int max = subTypes.length;
|
||||
for (int i = 0; i < max; i++) {
|
||||
var subType = subTypes[i];
|
||||
var subSerializerInstance = subType.getJSerializerInstance(basePackageName);
|
||||
method.addStatement("case $L -> ($T) $T.$N.deserialize(in)",
|
||||
i,
|
||||
subType.getJTypeName(basePackageName),
|
||||
subSerializerInstance.className(),
|
||||
subSerializerInstance.fieldName()
|
||||
);
|
||||
}
|
||||
method.beginControlFlow("default ->");
|
||||
method.addStatement("checkIdValidity(id)");
|
||||
method.addComment("Not reachable:");
|
||||
method.addStatement("throw new $T()", IllegalStateException.class);
|
||||
method.endControlFlow();
|
||||
method.addCode("$<};");
|
||||
|
||||
classBuilder.addMethod(method.build());
|
||||
}
|
||||
}
|
@ -10,11 +10,13 @@ import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeSpec.Builder;
|
||||
import com.squareup.javapoet.TypeVariableName;
|
||||
import it.cavallium.data.generator.DataSerializer;
|
||||
import it.cavallium.data.generator.DataUpgrader;
|
||||
import it.cavallium.data.generator.plugin.ClassGenerator;
|
||||
import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType;
|
||||
import it.cavallium.data.generator.plugin.ComputedTypeCustom;
|
||||
import it.cavallium.data.generator.plugin.ComputedVersion;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
@ -37,7 +39,7 @@ public class GenVersion extends ClassGenerator {
|
||||
classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
|
||||
var iVersionClassName = ClassName.get(dataModel.getRootPackage(basePackageName), "IVersion");
|
||||
var iBaseTypeClassName = ClassName.get(version.getDataPackage(basePackageName), "IBaseType");
|
||||
var iBaseTypeClassName = ClassName.get(version.getPackage(basePackageName), "IBaseType");
|
||||
classBuilder.addSuperinterface(ParameterizedTypeName.get(iVersionClassName, iBaseTypeClassName));
|
||||
|
||||
generateVersionField(version, classBuilder);
|
||||
@ -101,10 +103,10 @@ public class GenVersion extends ClassGenerator {
|
||||
methodBuilder.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);
|
||||
methodBuilder.addException(ClassName.get(IOException.class));
|
||||
|
||||
var nextIBaseType = ClassName.get(nextVersion.getDataPackage(basePackageName), "IBaseType");
|
||||
var nextIBaseType = ClassName.get(nextVersion.getPackage(basePackageName), "IBaseType");
|
||||
methodBuilder.returns(nextIBaseType);
|
||||
|
||||
var iBaseTypeClassName = ClassName.get(version.getDataPackage(basePackageName), "IBaseType");
|
||||
var iBaseTypeClassName = ClassName.get(version.getPackage(basePackageName), "IBaseType");
|
||||
methodBuilder.addParameter(iBaseTypeClassName, "oldData");
|
||||
|
||||
methodBuilder.beginControlFlow( "return switch (oldData.getBaseType$$())");
|
||||
@ -169,19 +171,24 @@ public class GenVersion extends ClassGenerator {
|
||||
var versionClassType = ClassName.get(version.getPackage(basePackageName), "Version");
|
||||
dataModel.getComputedTypes(version).forEach((typeName, type) -> {
|
||||
boolean shouldCreateInstanceField = type instanceof VersionedComputedType versionedComputedType
|
||||
&& versionedComputedType.getVersion().equals(version);
|
||||
&& versionedComputedType.getVersion().equals(version) && !version.isCurrent();
|
||||
if (!shouldCreateInstanceField) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nextVersion = Objects.requireNonNull(dataModel.getNextVersion(type));
|
||||
|
||||
var upgraderFieldLocation = type.getJUpgraderInstance(basePackageName);
|
||||
if (!versionClassType.equals(upgraderFieldLocation.className())) {
|
||||
return;
|
||||
}
|
||||
|
||||
var genericClassName = ParameterizedTypeName.get(ClassName.get(DataUpgrader.class),
|
||||
type.getJTypeName(basePackageName), nextVersion.getJTypeName(basePackageName)
|
||||
);
|
||||
var upgraderClassName = type.getJUpgraderName(basePackageName);
|
||||
|
||||
var fieldBuilder = FieldSpec.builder(upgraderClassName,
|
||||
var fieldBuilder = FieldSpec.builder(genericClassName,
|
||||
upgraderFieldLocation.fieldName(),
|
||||
Modifier.PUBLIC,
|
||||
Modifier.STATIC,
|
||||
@ -199,15 +206,16 @@ public class GenVersion extends ClassGenerator {
|
||||
methodBuilder.addAnnotation(Override.class);
|
||||
methodBuilder.addException(ClassName.get(IOException.class));
|
||||
|
||||
var iBaseTypeClassName = ClassName.get(version.getDataPackage(basePackageName), "IBaseType");
|
||||
var iBaseTypeClassName = ClassName.get(version.getPackage(basePackageName), "IBaseType");
|
||||
methodBuilder.addTypeVariable(TypeVariableName.get("T", iBaseTypeClassName));
|
||||
|
||||
var baseTypeClassName = ClassName.get(dataModel.getRootPackage(basePackageName), "BaseType");
|
||||
methodBuilder.addParameter(baseTypeClassName, "type");
|
||||
|
||||
methodBuilder.returns(ParameterizedTypeName.get(ClassName.get(DataSerializer.class), TypeVariableName.get("T")));
|
||||
var returnType = ParameterizedTypeName.get(ClassName.get(DataSerializer.class), TypeVariableName.get("T"));
|
||||
methodBuilder.returns(returnType);
|
||||
|
||||
methodBuilder.beginControlFlow("return switch (type)");
|
||||
methodBuilder.beginControlFlow("return ($T) switch (type)", returnType);
|
||||
dataModel.getBaseTypesComputed(version).forEach(baseType -> {
|
||||
var field = baseType.getJSerializerInstance(basePackageName);
|
||||
methodBuilder.addStatement("case $N -> $T.$N", baseType.getName(), field.className(), field.fieldName());
|
||||
|
@ -0,0 +1,682 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2022 Sebastiano Vigna
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package it.cavallium.data.generator.nativedata;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.AbstractObjectList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrays;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterators;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSpliterator;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSpliterators;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.RandomAccess;
|
||||
import java.util.function.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ImmutableWrappedArrayList<K> extends AbstractObjectList<K> implements RandomAccess {
|
||||
/** The backing array. */
|
||||
protected final K[] a;
|
||||
/** The current actual size of the list (never greater than the backing-array length). */
|
||||
protected final int size;
|
||||
|
||||
/**
|
||||
* Creates a new array list and fills it with the elements of a given array.
|
||||
*
|
||||
* @param a an array whose elements will be used to fill the array list.
|
||||
*/
|
||||
public ImmutableWrappedArrayList(final K[] a) {
|
||||
this.a = a;
|
||||
this.size = a.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array list using an array of elements.
|
||||
*
|
||||
* @param init a the array the will become the new backing array of the array list.
|
||||
* @return a new array list backed by the given array.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <K> ImmutableWrappedArrayList<K> of(final K... init) {
|
||||
return new ImmutableWrappedArrayList<>(init);
|
||||
}
|
||||
|
||||
private UnsupportedOperationException ex() {
|
||||
return new UnsupportedOperationException("Immutable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(final int index, final K k) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(final K k) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K get(final int index) {
|
||||
if (index >= size) throw new IndexOutOfBoundsException("Index (" + index + ") is greater than or equal to list size (" + size + ")");
|
||||
return a[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(final Object k) {
|
||||
for (int i = 0; i < size; i++) if (java.util.Objects.equals(k, a[i])) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(final Object k) {
|
||||
for (int i = size; i-- != 0;) if (java.util.Objects.equals(k, a[i])) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K remove(final int index) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(final Object k) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K set(final int index, final K k) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void size(final int size) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
private class SubList extends AbstractObjectList.ObjectRandomAccessSubList<K> {
|
||||
|
||||
protected SubList(int from, int to) {
|
||||
super(ImmutableWrappedArrayList.this, from, to);
|
||||
}
|
||||
|
||||
// Most of the inherited methods should be fine, but we can override a few of them for performance.
|
||||
// Needed because we can't access the parent class' instance variables directly in a different
|
||||
// instance of SubList.
|
||||
private K[] getParentArray() {
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K get(int i) {
|
||||
ensureRestrictedIndex(i);
|
||||
return a[i + from];
|
||||
}
|
||||
|
||||
private final class SubListIterator extends ObjectIterators.AbstractIndexBasedListIterator<K> {
|
||||
// We are using pos == 0 to be 0 relative to SubList.from (meaning you need to do a[from + i] when
|
||||
// accessing array).
|
||||
SubListIterator(int index) {
|
||||
super(0, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected K get(int i) {
|
||||
return a[from + i];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void add(int i, K k) {
|
||||
SubList.this.add(i, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void set(int i, K k) {
|
||||
SubList.this.set(i, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void remove(int i) {
|
||||
SubList.this.remove(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxPos() {
|
||||
return to - from;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
return a[from + (lastReturned = pos++)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public K previous() {
|
||||
if (!hasPrevious()) throw new NoSuchElementException();
|
||||
return a[from + (lastReturned = --pos)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachRemaining(final Consumer<? super K> action) {
|
||||
final int max = to - from;
|
||||
while (pos < max) {
|
||||
action.accept(a[from + (lastReturned = pos++)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ObjectListIterator<K> listIterator(int index) {
|
||||
return new SubListIterator(index);
|
||||
}
|
||||
|
||||
private final class SubListSpliterator extends ObjectSpliterators.LateBindingSizeIndexBasedSpliterator<K> {
|
||||
// We are using pos == 0 to be 0 relative to real array 0
|
||||
SubListSpliterator() {
|
||||
super(from);
|
||||
}
|
||||
|
||||
private SubListSpliterator(int pos, int maxPos) {
|
||||
super(pos, maxPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxPosFromBackingStore() {
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected K get(int i) {
|
||||
return a[i];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SubListSpliterator makeForSplit(int pos, int maxPos) {
|
||||
return new SubListSpliterator(pos, maxPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(final Consumer<? super K> action) {
|
||||
if (pos >= getMaxPos()) return false;
|
||||
action.accept(a[pos++]);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachRemaining(final Consumer<? super K> action) {
|
||||
final int max = getMaxPos();
|
||||
while (pos < max) {
|
||||
action.accept(a[pos++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectSpliterator<K> spliterator() {
|
||||
return new SubListSpliterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (o == null) return false;
|
||||
if (!(o instanceof java.util.List)) return false;
|
||||
if (o instanceof ImmutableWrappedArrayList) {
|
||||
@SuppressWarnings("unchecked") ImmutableWrappedArrayList<K> other = (ImmutableWrappedArrayList<K>)o;
|
||||
return Arrays.equals(a, from, to, other.a, 0, other.size());
|
||||
}
|
||||
if (o instanceof ImmutableWrappedArrayList.SubList) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ImmutableWrappedArrayList<K>.SubList other = (ImmutableWrappedArrayList<K>.SubList)o;
|
||||
return Arrays.equals(a, from, to, other.getParentArray(), other.from, other.to);
|
||||
}
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
int contentsCompareTo(K[] otherA, int otherAFrom, int otherATo) {
|
||||
return Arrays.compare(a, from, to, otherA, otherAFrom, otherATo, (o1, o2) -> ((Comparable<K>)o1).compareTo(o2));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public int compareTo(final java.util.List<? extends K> l) {
|
||||
if (l instanceof ImmutableWrappedArrayList) {
|
||||
@SuppressWarnings("unchecked") ImmutableWrappedArrayList<K> other = (ImmutableWrappedArrayList<K>)l;
|
||||
return contentsCompareTo(other.a, 0, other.size());
|
||||
}
|
||||
if (l instanceof ImmutableWrappedArrayList.SubList) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ImmutableWrappedArrayList<K>.SubList other = (ImmutableWrappedArrayList<K>.SubList)l;
|
||||
return contentsCompareTo(other.getParentArray(), other.from, other.to);
|
||||
}
|
||||
return super.compareTo(l);
|
||||
}
|
||||
// We don't override subList as we want AbstractList's "sub-sublist" nesting handling,
|
||||
// which would be tricky to do here.
|
||||
// TODO Do override it so array access isn't sent through N indirections.
|
||||
// This will likely mean making this class static.
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectList<K> subList(int from, int to) {
|
||||
if (from == 0 && to == size()) return this;
|
||||
ensureIndex(from);
|
||||
ensureIndex(to);
|
||||
if (from > to) throw new IndexOutOfBoundsException("Start index (" + from + ") is greater than end index (" + to + ")");
|
||||
return new SubList(from, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies element of this type-specific list into the given array using optimized system calls.
|
||||
*
|
||||
* @param from the start index (inclusive).
|
||||
* @param a the destination array.
|
||||
* @param offset the offset into the destination array where to store the first element copied.
|
||||
* @param length the number of elements to be copied.
|
||||
*/
|
||||
@Override
|
||||
public void getElements(final int from, final Object[] a, final int offset, final int length) {
|
||||
ObjectArrays.ensureOffsetLength(a, offset, length);
|
||||
System.arraycopy(this.a, from, a, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes elements of this type-specific list using optimized system calls.
|
||||
*
|
||||
* @param from the start index (inclusive).
|
||||
* @param to the end index (exclusive).
|
||||
*/
|
||||
@Override
|
||||
public void removeElements(final int from, final int to) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds elements to this type-specific list using optimized system calls.
|
||||
*
|
||||
* @param index the index at which to add elements.
|
||||
* @param a the array containing the elements.
|
||||
* @param offset the offset of the first element to add.
|
||||
* @param length the number of elements to add.
|
||||
*/
|
||||
@Override
|
||||
public void addElements(final int index, final K[] a, final int offset, final int length) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets elements to this type-specific list using optimized system calls.
|
||||
*
|
||||
* @param index the index at which to start setting elements.
|
||||
* @param a the array containing the elements.
|
||||
* @param offset the offset of the first element to add.
|
||||
* @param length the number of elements to add.
|
||||
*/
|
||||
@Override
|
||||
public void setElements(final int index, final K[] a, final int offset, final int length) {
|
||||
ensureIndex(index);
|
||||
ObjectArrays.ensureOffsetLength(a, offset, length);
|
||||
if (index + length > size) throw new IndexOutOfBoundsException("End index (" + (index + length) + ") is greater than list size (" + size + ")");
|
||||
System.arraycopy(a, offset, this.a, index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(final Consumer<? super K> action) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
action.accept(a[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, final Collection<? extends K> c) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(final int index, final ObjectList<? extends K> l) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(final @NotNull Collection<?> c) {
|
||||
throw ex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
final int size = size();
|
||||
// A subtle part of the spec says the returned array must be Object[] exactly.
|
||||
if (size == 0) return it.unimi.dsi.fastutil.objects.ObjectArrays.EMPTY_ARRAY;
|
||||
return Arrays.copyOf(a, size, Object[].class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <K2> K2[] toArray(K2[] a) {
|
||||
if (a == null) {
|
||||
a = (K2[])new Object[size()];
|
||||
} else if (a.length < size()) {
|
||||
a = (K2[])Array.newInstance(a.getClass().getComponentType(), size());
|
||||
}
|
||||
//noinspection ReassignedVariable,SuspiciousSystemArraycopy
|
||||
System.arraycopy(this.a, 0, a, 0, size());
|
||||
if (a.length > size()) {
|
||||
a[size()] = null;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectListIterator<K> listIterator(final int index) {
|
||||
ensureIndex(index);
|
||||
return new ObjectListIterator<>() {
|
||||
int pos = index, last = -1;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return pos < size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return pos > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return a[last = pos++];
|
||||
}
|
||||
|
||||
@Override
|
||||
public K previous() {
|
||||
if (!hasPrevious()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return a[last = --pos];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextIndex() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previousIndex() {
|
||||
return pos - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(K k) {
|
||||
ImmutableWrappedArrayList.this.add(pos++, k);
|
||||
last = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(K k) {
|
||||
if (last == -1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
ImmutableWrappedArrayList.this.set(last, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (last == -1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
ImmutableWrappedArrayList.this.remove(last);
|
||||
/* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */
|
||||
if (last < pos) {
|
||||
pos--;
|
||||
}
|
||||
last = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachRemaining(final Consumer<? super K> action) {
|
||||
while (pos < size) {
|
||||
action.accept(a[last = pos++]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int back(int n) {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("Argument must be nonnegative: " + n);
|
||||
}
|
||||
final int remaining = size - pos;
|
||||
if (n < remaining) {
|
||||
pos -= n;
|
||||
} else {
|
||||
n = remaining;
|
||||
pos = 0;
|
||||
}
|
||||
last = pos;
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int skip(int n) {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("Argument must be nonnegative: " + n);
|
||||
}
|
||||
final int remaining = size - pos;
|
||||
if (n < remaining) {
|
||||
pos += n;
|
||||
} else {
|
||||
n = remaining;
|
||||
pos = size;
|
||||
}
|
||||
last = pos - 1;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// If you update this, you will probably want to update ArraySet as well
|
||||
private final class Spliterator implements ObjectSpliterator<K> {
|
||||
// Until we split, we will track the size of the list.
|
||||
// Once we split, then we stop updating on structural modifications.
|
||||
// Aka, size is late-binding.
|
||||
boolean hasSplit;
|
||||
int pos, max;
|
||||
|
||||
public Spliterator() {
|
||||
this(0, ImmutableWrappedArrayList.this.size, false);
|
||||
}
|
||||
|
||||
private Spliterator(int pos, int max, boolean hasSplit) {
|
||||
assert pos <= max : "pos " + pos + " must be <= max " + max;
|
||||
this.pos = pos;
|
||||
this.max = max;
|
||||
this.hasSplit = hasSplit;
|
||||
}
|
||||
|
||||
private int getWorkingMax() {
|
||||
return hasSplit ? max : ImmutableWrappedArrayList.this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return ObjectSpliterators.LIST_SPLITERATOR_CHARACTERISTICS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() {
|
||||
return getWorkingMax() - pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(final Consumer<? super K> action) {
|
||||
if (pos >= getWorkingMax()) return false;
|
||||
action.accept(a[pos++]);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachRemaining(final Consumer<? super K> action) {
|
||||
for (final int max = getWorkingMax(); pos < max; ++pos) {
|
||||
action.accept(a[pos]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) {
|
||||
if (n < 0) throw new IllegalArgumentException("Argument must be nonnegative: " + n);
|
||||
final int max = getWorkingMax();
|
||||
if (pos >= max) return 0;
|
||||
final int remaining = max - pos;
|
||||
if (n < remaining) {
|
||||
pos = it.unimi.dsi.fastutil.SafeMath.safeLongToInt(pos + n);
|
||||
return n;
|
||||
}
|
||||
n = remaining;
|
||||
pos = max;
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectSpliterator<K> trySplit() {
|
||||
final int max = getWorkingMax();
|
||||
int retLen = (max - pos) >> 1;
|
||||
if (retLen <= 1) return null;
|
||||
// Update instance max with the last seen list size (if needed) before continuing
|
||||
this.max = max;
|
||||
int myNewPos = pos + retLen;
|
||||
int oldPos = pos;
|
||||
this.pos = myNewPos;
|
||||
this.hasSplit = true;
|
||||
return new Spliterator(oldPos, myNewPos, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* The returned spliterator is late-binding; it will track structural changes after the current
|
||||
* index, up until the first {@link java.util.Spliterator#trySplit() trySplit()}, at which point the
|
||||
* maximum index will be fixed. <br>
|
||||
* Structural changes before the current index or after the first
|
||||
* {@link java.util.Spliterator#trySplit() trySplit()} will result in unspecified behavior.
|
||||
*/
|
||||
@Override
|
||||
public ObjectSpliterator<K> spliterator() {
|
||||
// If it wasn't for the possibility of the list being expanded or shrunk,
|
||||
// we could return SPLITERATORS.wrap(a, 0, size).
|
||||
return new Spliterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sort(final Comparator<? super K> comp) {
|
||||
if (comp == null) {
|
||||
ObjectArrays.stableSort(a, 0, size);
|
||||
} else {
|
||||
ObjectArrays.stableSort(a, 0, size, comp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unstableSort(final Comparator<? super K> comp) {
|
||||
if (comp == null) {
|
||||
ObjectArrays.unstableSort(a, 0, size);
|
||||
} else {
|
||||
ObjectArrays.unstableSort(a, 0, size, comp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this type-specific array list to another one.
|
||||
*
|
||||
* @apiNote This method exists only for sake of efficiency. The implementation inherited from the
|
||||
* abstract implementation would already work.
|
||||
*
|
||||
* @param l a type-specific array list.
|
||||
* @return true if the argument contains the same elements of this type-specific array list.
|
||||
*/
|
||||
public boolean equals(final ImmutableWrappedArrayList<K> l) {
|
||||
return Arrays.equals(a, 0, size(), l.a, 0, l.size());
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "unlikely-arg-type" })
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (o == this) return true;
|
||||
if (o == null) return false;
|
||||
if (!(o instanceof java.util.List)) return false;
|
||||
if (o instanceof ImmutableWrappedArrayList) {
|
||||
// Safe cast because we are only going to take elements from other list, never give them
|
||||
return equals((ImmutableWrappedArrayList<K>)o);
|
||||
}
|
||||
if (o instanceof ImmutableWrappedArrayList.SubList) {
|
||||
// Safe cast because we are only going to take elements from other list, never give them
|
||||
// Sublist has an optimized sub-array based comparison, reuse that.
|
||||
return o.equals(this);
|
||||
}
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this array list to another array list.
|
||||
*
|
||||
* @apiNote This method exists only for sake of efficiency. The implementation inherited from the
|
||||
* abstract implementation would already work.
|
||||
*
|
||||
* @param l an array list.
|
||||
* @return a negative integer, zero, or a positive integer as this list is lexicographically less
|
||||
* than, equal to, or greater than the argument.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public int compareTo(final ImmutableWrappedArrayList<? extends K> l) {
|
||||
return Arrays.compare(a, 0, size(), l.a, 0, l.size(), (o1, o2) -> ((Comparable<K>) o1).compareTo(o2));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public int compareTo(final java.util.List<? extends K> l) {
|
||||
if (l instanceof ImmutableWrappedArrayList) {
|
||||
return compareTo((ImmutableWrappedArrayList<? extends K>)l);
|
||||
}
|
||||
if (l instanceof ImmutableWrappedArrayList.SubList) {
|
||||
// Must negate because we are inverting the order of the comparison.
|
||||
return -((ImmutableWrappedArrayList<K>.SubList)l).compareTo(this);
|
||||
}
|
||||
return super.compareTo(l);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user