Compute all types
This commit is contained in:
parent
f6fe7017c7
commit
4485dd675f
@ -0,0 +1,487 @@
|
||||
package it.cavallium.data.generator.plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public sealed interface ComputedType {
|
||||
|
||||
String getName();
|
||||
|
||||
sealed interface VersionedComputedType extends ComputedType {
|
||||
|
||||
int getVersion();
|
||||
|
||||
ComputedType withChangeAtVersion(int version, VersionChangeChecker versionChangeChecker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all types that are required by this type
|
||||
*/
|
||||
Stream<ComputedType> getDependencies();
|
||||
|
||||
/**
|
||||
* Get all types that require this type
|
||||
*/
|
||||
Stream<ComputedType> getDependents();
|
||||
|
||||
final class ComputedBaseType implements VersionedComputedType {
|
||||
|
||||
private final VersionedType type;
|
||||
private final String stringRepresenter;
|
||||
|
||||
private final LinkedHashMap<String, VersionedType> data;
|
||||
private LinkedHashMap<String, ComputedType> computedData;
|
||||
private final ComputedTypeSupplier computedTypeSupplier;
|
||||
|
||||
public ComputedBaseType(VersionedType type,
|
||||
String stringRepresenter,
|
||||
LinkedHashMap<String, VersionedType> data,
|
||||
ComputedTypeSupplier computedTypeSupplier) {
|
||||
this.type = type;
|
||||
if (type.type().startsWith("~") || type.type().startsWith("-")) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
this.computedTypeSupplier = computedTypeSupplier;
|
||||
this.stringRepresenter = stringRepresenter;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return type.version();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComputedBaseType withChangeAtVersion(int version, VersionChangeChecker versionChangeChecker) {
|
||||
var newData = new LinkedHashMap<String, VersionedType>();
|
||||
data.forEach((k, v) -> newData.put(k, v.withVersionIfChanged(version, versionChangeChecker)));
|
||||
return new ComputedBaseType(type.withVersion(version), stringRepresenter, newData, computedTypeSupplier);
|
||||
}
|
||||
|
||||
public String getStringRepresenter() {
|
||||
return stringRepresenter;
|
||||
}
|
||||
|
||||
public LinkedHashMap<String, ComputedType> getData() {
|
||||
synchronized (this) {
|
||||
if (computedData == null) {
|
||||
computedData = new LinkedHashMap<>();
|
||||
data.forEach((k, v) -> computedData.put(k, computedTypeSupplier.get(v)));
|
||||
}
|
||||
}
|
||||
return computedData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComputedBaseType that = (ComputedBaseType) o;
|
||||
|
||||
if (!Objects.equals(type, that.type)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(stringRepresenter, that.stringRepresenter)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(data, that.data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = type != null ? type.hashCode() : 0;
|
||||
result = 31 * result + (stringRepresenter != null ? stringRepresenter.hashCode() : 0);
|
||||
result = 31 * result + (data != null ? data.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return type.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependencies() {
|
||||
return this.data.values().stream().map(computedTypeSupplier::get);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependents() {
|
||||
return computedTypeSupplier.getDependents(type);
|
||||
}
|
||||
}
|
||||
|
||||
final class ComputedCustomType implements ComputedType {
|
||||
|
||||
private final String type;
|
||||
private final String javaClass;
|
||||
private final String serializer;
|
||||
private final ComputedTypeSupplier computedTypeSupplier;
|
||||
|
||||
public ComputedCustomType(String type, String javaClass, String serializer, ComputedTypeSupplier computedTypeSupplier) {
|
||||
this.type = type;
|
||||
this.javaClass = javaClass;
|
||||
this.serializer = serializer;
|
||||
this.computedTypeSupplier = computedTypeSupplier;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getJavaClass() {
|
||||
return javaClass;
|
||||
}
|
||||
|
||||
public String getSerializer() {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComputedCustomType that = (ComputedCustomType) o;
|
||||
|
||||
if (!Objects.equals(type, that.type)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(javaClass, that.javaClass)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(serializer, that.serializer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = type != null ? type.hashCode() : 0;
|
||||
result = 31 * result + (javaClass != null ? javaClass.hashCode() : 0);
|
||||
result = 31 * result + (serializer != null ? serializer.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependencies() {
|
||||
return Stream.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependents() {
|
||||
return computedTypeSupplier.getDependents(new VersionedType(type, 0));
|
||||
}
|
||||
}
|
||||
|
||||
final class ComputedNullableType implements VersionedComputedType {
|
||||
|
||||
private final VersionedType baseType;
|
||||
|
||||
private ComputedType computedChild;
|
||||
private final ComputedTypeSupplier computedTypeSupplier;
|
||||
|
||||
public ComputedNullableType(VersionedType baseType, ComputedTypeSupplier computedTypeSupplier) {
|
||||
this.baseType = baseType;
|
||||
this.computedTypeSupplier = computedTypeSupplier;
|
||||
}
|
||||
|
||||
public String getBaseType() {
|
||||
return baseType.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return baseType.version();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComputedNullableType withChangeAtVersion(int version, VersionChangeChecker versionChangeChecker) {
|
||||
return new ComputedNullableType(baseType.withVersion(version), computedTypeSupplier);
|
||||
}
|
||||
|
||||
public ComputedType child() {
|
||||
synchronized (this) {
|
||||
if (computedChild == null) {
|
||||
computedChild = computedTypeSupplier.get(baseType);
|
||||
}
|
||||
}
|
||||
if (computedChild instanceof ComputedNullableType) {
|
||||
throw new IllegalStateException();
|
||||
} else if (computedChild instanceof ComputedArrayType) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return computedChild;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComputedNullableType that = (ComputedNullableType) o;
|
||||
|
||||
return Objects.equals(baseType, that.baseType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return baseType != null ? baseType.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "-" + baseType.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependencies() {
|
||||
return Stream.of(child());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependents() {
|
||||
return computedTypeSupplier.getDependents(new VersionedType(getName(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
final class ComputedSuperType implements VersionedComputedType {
|
||||
|
||||
private final VersionedType type;
|
||||
private final List<VersionedType> subTypes;
|
||||
|
||||
private List<ComputedType> computedSubTypes;
|
||||
private final ComputedTypeSupplier computedTypeSupplier;
|
||||
|
||||
public ComputedSuperType(VersionedType type,
|
||||
List<VersionedType> subType,
|
||||
ComputedTypeSupplier computedTypeSupplier) {
|
||||
this.type = type;
|
||||
this.subTypes = subType;
|
||||
this.computedTypeSupplier = computedTypeSupplier;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return type.version();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComputedSuperType withChangeAtVersion(int version, VersionChangeChecker versionChangeChecker) {
|
||||
return new ComputedSuperType(type.withVersion(version),
|
||||
subTypes.stream().map(subType -> subType.withVersionIfChanged(version, versionChangeChecker)).toList(),
|
||||
computedTypeSupplier
|
||||
);
|
||||
}
|
||||
|
||||
public List<ComputedType> subTypes() {
|
||||
synchronized (this) {
|
||||
if (computedSubTypes == null) {
|
||||
computedSubTypes = new ArrayList<>();
|
||||
for (VersionedType subType : subTypes) {
|
||||
computedSubTypes.add(computedTypeSupplier.get(subType));
|
||||
}
|
||||
}
|
||||
}
|
||||
return computedSubTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComputedSuperType that = (ComputedSuperType) o;
|
||||
|
||||
if (!Objects.equals(type, that.type)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(subTypes, that.subTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = type != null ? type.hashCode() : 0;
|
||||
result = 31 * result + (subTypes != null ? subTypes.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependencies() {
|
||||
return subTypes().stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependents() {
|
||||
return computedTypeSupplier.getDependents(new VersionedType(getName(), 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return type.type();
|
||||
}
|
||||
}
|
||||
|
||||
final class ComputedArrayType implements VersionedComputedType {
|
||||
|
||||
private final VersionedType baseType;
|
||||
|
||||
private ComputedType computedChild;
|
||||
private final ComputedTypeSupplier computedTypeSupplier;
|
||||
|
||||
public ComputedArrayType(VersionedType baseType, ComputedTypeSupplier computedTypeSupplier) {
|
||||
this.baseType = baseType;
|
||||
this.computedTypeSupplier = computedTypeSupplier;
|
||||
}
|
||||
|
||||
public String getBaseType() {
|
||||
return baseType.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return baseType.version();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComputedArrayType withChangeAtVersion(int version, VersionChangeChecker versionChangeChecker) {
|
||||
return new ComputedArrayType(baseType.withVersion(version), computedTypeSupplier);
|
||||
}
|
||||
|
||||
public ComputedType child() {
|
||||
synchronized (this) {
|
||||
if (computedChild == null) {
|
||||
computedChild = computedTypeSupplier.get(baseType);
|
||||
}
|
||||
}
|
||||
if (computedChild instanceof ComputedNullableType) {
|
||||
throw new IllegalStateException();
|
||||
} else if (computedChild instanceof ComputedArrayType) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return computedChild;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComputedArrayType that = (ComputedArrayType) o;
|
||||
|
||||
return Objects.equals(baseType, that.baseType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return baseType != null ? baseType.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "§" + baseType.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependencies() {
|
||||
return Stream.of(child());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependents() {
|
||||
return computedTypeSupplier.getDependents(new VersionedType(getName(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
final class ComputedNativeType implements ComputedType {
|
||||
|
||||
private final String type;
|
||||
private final ComputedTypeSupplier computedTypeSupplier;
|
||||
|
||||
public ComputedNativeType(String type, ComputedTypeSupplier computedTypeSupplier) {
|
||||
this.type = type;
|
||||
this.computedTypeSupplier = computedTypeSupplier;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComputedNativeType that = (ComputedNativeType) o;
|
||||
|
||||
return Objects.equals(type, that.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return type != null ? type.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependencies() {
|
||||
return Stream.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComputedType> getDependents() {
|
||||
return computedTypeSupplier.getDependents(new VersionedType(getName(), 0));
|
||||
}
|
||||
|
||||
public static List<ComputedNativeType> get(ComputedTypeSupplier computedTypeSupplier) {
|
||||
return Stream.of("String",
|
||||
"boolean",
|
||||
"short",
|
||||
"char",
|
||||
"int",
|
||||
"long",
|
||||
"float",
|
||||
"double",
|
||||
"byte",
|
||||
"Int52").map(name -> new ComputedNativeType(name, computedTypeSupplier)).toList();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package it.cavallium.data.generator.plugin;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ComputedTypeSupplier {
|
||||
|
||||
private final Int2ObjectMap<Map<String, ComputedType>> computedTypeMap;
|
||||
private final Int2ObjectMap<Map<String, List<ComputedType>>> computedTypeDependentsCacheMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
public ComputedTypeSupplier(Int2ObjectMap<Map<String, ComputedType>> computedTypeMap) {
|
||||
this.computedTypeMap = computedTypeMap;
|
||||
}
|
||||
|
||||
public ComputedType get(VersionedType type) {
|
||||
var computedType = computedTypeMap.get(type.version()).get(type.type());
|
||||
if (computedType == null) {
|
||||
throw new IllegalStateException("Type " + type + " does not exist");
|
||||
}
|
||||
return computedType;
|
||||
}
|
||||
|
||||
public Stream<ComputedType> getDependencies(VersionedType type) {
|
||||
return computedTypeMap.get(type.version()).get(type.type()).getDependencies();
|
||||
}
|
||||
|
||||
public Stream<ComputedType> getDependents(VersionedType type) {
|
||||
synchronized (computedTypeDependentsCacheMap) {
|
||||
return computedTypeDependentsCacheMap
|
||||
.computeIfAbsent(type.version(), x -> new HashMap<>())
|
||||
.computeIfAbsent(type.type(),
|
||||
typeName -> computedTypeMap.get(type.version()).values().stream().filter(computedType ->
|
||||
computedType.getDependencies().anyMatch(y -> Objects.equals(y.getName(), typeName))).toList())
|
||||
.stream();
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,10 @@ public final class CustomTypesConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
public String getJavaClassString() {
|
||||
return javaClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
|
@ -1,13 +1,22 @@
|
||||
package it.cavallium.data.generator.plugin;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.function.Function.identity;
|
||||
|
||||
import it.cavallium.data.generator.plugin.ComputedType.ComputedArrayType;
|
||||
import it.cavallium.data.generator.plugin.ComputedType.ComputedBaseType;
|
||||
import it.cavallium.data.generator.plugin.ComputedType.ComputedCustomType;
|
||||
import it.cavallium.data.generator.plugin.ComputedType.ComputedNativeType;
|
||||
import it.cavallium.data.generator.plugin.ComputedType.ComputedNullableType;
|
||||
import it.cavallium.data.generator.plugin.ComputedType.ComputedSuperType;
|
||||
import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -15,6 +24,7 @@ import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
@ -36,12 +46,12 @@ public class DataModel {
|
||||
);
|
||||
|
||||
private final int currentVersion;
|
||||
private final Int2ObjectMap<Map<String, ParsedClass>> classConfig;
|
||||
private final int hash;
|
||||
private final Map<String, ParsedInterface> interfacesData;
|
||||
private final Int2ObjectMap<ComputedVersion> versions;
|
||||
private final Map<String, Set<String>> superTypes;
|
||||
private final Map<String, CustomTypesConfiguration> customTypes;
|
||||
private final Int2ObjectMap<Map<String, ComputedType>> computedTypes;
|
||||
|
||||
public DataModel(int hash,
|
||||
String currentVersionKey,
|
||||
@ -95,7 +105,7 @@ public class DataModel {
|
||||
// Build versions sequence
|
||||
List<String> rawVersionsSequence = new ArrayList<>();
|
||||
int versionsCount = 0;
|
||||
Int2ObjectMap<String> versionToName = new Int2ObjectOpenHashMap<>();
|
||||
Int2ObjectMap<String> versionToName = new Int2ObjectLinkedOpenHashMap<>();
|
||||
Object2IntMap<String> nameToVersion = new Object2IntOpenHashMap<>();
|
||||
{
|
||||
String lastVersion = null;
|
||||
@ -132,7 +142,7 @@ public class DataModel {
|
||||
|
||||
Stream.concat(Stream.concat(Stream.concat(baseTypes.stream(), superTypes.stream()),
|
||||
customTypes.stream()), NATIVE_TYPES.stream())
|
||||
.collect(Collectors.groupingBy(Function.identity()))
|
||||
.collect(Collectors.groupingBy(identity()))
|
||||
.values()
|
||||
.stream()
|
||||
.filter(x -> x.size() > 1)
|
||||
@ -142,10 +152,10 @@ public class DataModel {
|
||||
});
|
||||
|
||||
// Compute the numeric versions map
|
||||
Int2ObjectMap<ParsedVersion> versions = new Int2ObjectOpenHashMap<>();
|
||||
Int2ObjectMap<ParsedVersion> versions = new Int2ObjectLinkedOpenHashMap<>();
|
||||
rawVersions.forEach((k, v) -> versions.put(nameToVersion.getInt(k), new ParsedVersion(v)));
|
||||
|
||||
Int2ObjectMap<Map<String, ParsedClass>> computedClassConfig = new Int2ObjectOpenHashMap<>();
|
||||
Int2ObjectMap<Map<String, ParsedClass>> computedClassConfig = new Int2ObjectLinkedOpenHashMap<>();
|
||||
for (int versionIndex = 0; versionIndex < versionsCount; versionIndex++) {
|
||||
if (versionIndex == 0) {
|
||||
computedClassConfig.put(0, baseTypesData.entrySet().stream()
|
||||
@ -179,6 +189,7 @@ public class DataModel {
|
||||
throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: "
|
||||
+ t.transformClass);
|
||||
}
|
||||
transformClass.changed = true;
|
||||
var definition = removeAndGetIndex(transformClass.data, t.from);
|
||||
if (definition.isEmpty()) {
|
||||
throw new IllegalArgumentException(transformCoordinate + " refers to an unknown field: " + t.from);
|
||||
@ -201,6 +212,7 @@ public class DataModel {
|
||||
throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: "
|
||||
+ t.transformClass);
|
||||
}
|
||||
transformClass.changed = true;
|
||||
if (!allTypes.contains(extractTypeName(t.type))) {
|
||||
throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: " + t.type);
|
||||
}
|
||||
@ -223,6 +235,7 @@ public class DataModel {
|
||||
throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: "
|
||||
+ t.transformClass);
|
||||
}
|
||||
transformClass.changed = true;
|
||||
var prevDef = transformClass.data.remove(t.from);
|
||||
if (prevDef == null) {
|
||||
throw new IllegalArgumentException(transformCoordinate + " tries to remove the nonexistent field \""
|
||||
@ -236,6 +249,7 @@ public class DataModel {
|
||||
throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: "
|
||||
+ t.transformClass);
|
||||
}
|
||||
transformClass.changed = true;
|
||||
if (!allTypes.contains(extractTypeName(t.type))) {
|
||||
throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: " + t.type);
|
||||
}
|
||||
@ -252,7 +266,133 @@ public class DataModel {
|
||||
}
|
||||
}
|
||||
|
||||
this.classConfig = computedClassConfig;
|
||||
Int2ObjectMap<Map<String, ComputedType>> computedTypes = new Int2ObjectLinkedOpenHashMap<>();
|
||||
ComputedTypeSupplier computedTypeSupplier = new ComputedTypeSupplier(computedTypes);
|
||||
for (int versionIndex = 0; versionIndex < versionsCount; versionIndex++) {
|
||||
int versionIndexF = versionIndex;
|
||||
if (versionIndexF == 0) {
|
||||
// Compute base types
|
||||
List<ComputedType> versionBaseTypes = computedClassConfig.get(versionIndexF).entrySet().stream()
|
||||
.map(e -> {
|
||||
var data = new LinkedHashMap<String, VersionedType>();
|
||||
e.getValue().getData().forEach((key, value) -> data.put(key, new VersionedType(value, versionIndexF)));
|
||||
return new ComputedBaseType(new VersionedType(e.getKey(), versionIndexF),
|
||||
e.getValue().stringRepresenter, data, computedTypeSupplier);
|
||||
}).collect(Collectors.toList());
|
||||
// Compute custom types
|
||||
customTypesData.forEach((name, data) -> versionBaseTypes.add(new ComputedCustomType(name,
|
||||
data.getJavaClassString(), data.serializer, computedTypeSupplier)));
|
||||
// Compute super types
|
||||
superTypesData.forEach((key, data) -> {
|
||||
List<VersionedType> subTypes = data.stream().map(x -> new VersionedType(x, versionIndexF)).toList();
|
||||
versionBaseTypes.add(new ComputedSuperType(new VersionedType(key, versionIndexF), subTypes, computedTypeSupplier));
|
||||
});
|
||||
// Compute nullable types
|
||||
computedClassConfig.values().stream()
|
||||
.flatMap(x -> x.values().stream())
|
||||
.flatMap(x -> x.getData().values().stream())
|
||||
.filter(x -> x.startsWith("-"))
|
||||
.map(nullableName -> new VersionedType(nullableName.substring(1), versionIndexF))
|
||||
.map(baseType -> new ComputedNullableType(baseType, computedTypeSupplier))
|
||||
.forEach(versionBaseTypes::add);
|
||||
// Compute array types
|
||||
computedClassConfig.values().stream()
|
||||
.flatMap(x -> x.values().stream())
|
||||
.flatMap(x -> x.getData().values().stream())
|
||||
.filter(x -> x.startsWith("§"))
|
||||
.map(nullableName -> new VersionedType(nullableName.substring(1), versionIndexF))
|
||||
.map(baseType -> new ComputedArrayType(baseType, computedTypeSupplier))
|
||||
.forEach(versionBaseTypes::add);
|
||||
// Compute native types
|
||||
versionBaseTypes.addAll(ComputedNativeType.get(computedTypeSupplier));
|
||||
|
||||
computedTypes.put(versionIndexF,
|
||||
versionBaseTypes.stream().distinct().collect(Collectors.toMap(ComputedType::getName, identity())));
|
||||
} else {
|
||||
Set<String> changedTypes = computedTypes.get(versionIndexF - 1).values().stream()
|
||||
.filter(prevType -> prevType instanceof ComputedBaseType prevBaseType
|
||||
&& computedClassConfig.get(versionIndexF).get(prevBaseType.getName()).changed)
|
||||
.map(ComputedType::getName)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
{
|
||||
boolean addedMoreTypes;
|
||||
do {
|
||||
var newChangedTypes = changedTypes
|
||||
.parallelStream()
|
||||
.flatMap(changedType -> computedTypes.get(versionIndexF - 1).get(changedType).getDependents())
|
||||
.map(ComputedType::getName)
|
||||
.distinct()
|
||||
.toList();
|
||||
addedMoreTypes = changedTypes.addAll(newChangedTypes);
|
||||
} while (addedMoreTypes);
|
||||
}
|
||||
|
||||
Map<String, ComputedType> currentVersionComputedTypes = new HashMap<>();
|
||||
var versionChangeChecker = new VersionChangeChecker(changedTypes);
|
||||
computedTypes.get(versionIndexF - 1).forEach((name, type) -> {
|
||||
if (!changedTypes.contains(name)) {
|
||||
currentVersionComputedTypes.put(name, type);
|
||||
} else {
|
||||
if (type instanceof VersionedComputedType versionedComputedType) {
|
||||
ComputedType newType = versionedComputedType.withChangeAtVersion(versionIndexF, versionChangeChecker);
|
||||
currentVersionComputedTypes.put(name, newType);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
});
|
||||
computedTypes.put(versionIndexF, currentVersionComputedTypes);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Example upgrade:
|
||||
|
||||
V001======================================
|
||||
_Message v1
|
||||
|__MessageForwardOrigin v1
|
||||
|__MessageText v1
|
||||
|
||||
_MessageText
|
||||
|
||||
_MessageForwardOrigin v1
|
||||
|__MessageForwardOriginChat v1
|
||||
|
||||
_MessageForwardOriginChat v1
|
||||
|__ChatEntityId v1
|
||||
|
||||
_UserId v1
|
||||
|
||||
_ChatEntityId v1
|
||||
|__UserId v1
|
||||
|__SupergroupId v1
|
||||
|__BaseGroupId v1
|
||||
|
||||
|
||||
V002======================================
|
||||
* UserId changed
|
||||
==========================================
|
||||
_Message v2 *
|
||||
|__MessageForwardOrigin v2 *
|
||||
|__MessageText v1
|
||||
|
||||
_MessageText v1
|
||||
|
||||
_MessageForwardOrigin v2 *
|
||||
|__MessageForwardOriginChat v2 *
|
||||
|
||||
_MessageForwardOriginChat v2 *
|
||||
|__ChatEntityId v2 *
|
||||
|
||||
_UserId v2 *
|
||||
|
||||
_ChatEntityId v2 *
|
||||
|__UserId v2 *
|
||||
|__SupergroupId v1
|
||||
|__BaseGroupId v1
|
||||
*/
|
||||
|
||||
this.interfacesData = interfacesData.entrySet().stream()
|
||||
.map(e -> Map.entry(e.getKey(), new ParsedInterface(e.getValue())))
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
|
||||
@ -269,11 +409,30 @@ public class DataModel {
|
||||
(a, b) -> {
|
||||
throw new IllegalStateException();
|
||||
},
|
||||
Int2ObjectOpenHashMap::new
|
||||
Int2ObjectLinkedOpenHashMap::new
|
||||
));
|
||||
LongAdder unchangedTot = new LongAdder();
|
||||
LongAdder changedTot = new LongAdder();
|
||||
computedTypes.forEach((version, types) -> {
|
||||
System.out.println("Version: " + version);
|
||||
System.out.println("\tTypes: " + types.size());
|
||||
System.out.println("\tVersioned types: " + types.values().stream().filter(t -> (t instanceof VersionedComputedType)).count());
|
||||
var unchanged = types.values().stream().filter(t -> (t instanceof VersionedComputedType versionedComputedType && versionedComputedType.getVersion() < version)).count();
|
||||
var changed = types.values().stream().filter(t -> (t instanceof VersionedComputedType versionedComputedType && versionedComputedType.getVersion() == version)).count();
|
||||
unchangedTot.add(unchanged);
|
||||
changedTot.add(changed);
|
||||
System.out.println("\t\tUnchanged: " + unchanged + " (" + (unchanged * 100 / (changed + unchanged)) + "%)");
|
||||
System.out.println("\t\tChanged: " + changed + " (" + (changed * 100 / (changed + unchanged)) + "%)");
|
||||
});
|
||||
System.out.println("Result:");
|
||||
var unchanged = unchangedTot.sum();
|
||||
var changed = changedTot.sum();
|
||||
System.out.println("\tAvoided type versions: " + unchanged + " (" + (unchanged * 100 / (changed + unchanged)) + "%)");
|
||||
System.out.println("\tType versions: " + changed + " (" + (changed * 100 / (changed + unchanged)) + "%)");
|
||||
this.currentVersion = versionsCount - 1;
|
||||
this.superTypes = superTypesData;
|
||||
this.customTypes = customTypesData;
|
||||
this.computedTypes = computedTypes;
|
||||
}
|
||||
|
||||
private String tryInsertAtIndex(LinkedHashMap<String, String> data, String key, String value, int index) {
|
||||
@ -429,4 +588,8 @@ public class DataModel {
|
||||
public Map<String, CustomTypesConfiguration> getCustomTypes() {
|
||||
return customTypes;
|
||||
}
|
||||
|
||||
public Int2ObjectMap<Map<String, ComputedType>> getComputedTypes() {
|
||||
return computedTypes;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package it.cavallium.data.generator.plugin;
|
||||
|
||||
import static it.cavallium.data.generator.plugin.DataModel.fixType;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@ -13,6 +14,7 @@ public final class ParsedClass {
|
||||
public String stringRepresenter;
|
||||
|
||||
public LinkedHashMap<String, String> data;
|
||||
public boolean changed;
|
||||
|
||||
public ParsedClass(ClassConfiguration baseTypesData) {
|
||||
this.stringRepresenter = baseTypesData.stringRepresenter;
|
||||
|
@ -0,0 +1,16 @@
|
||||
package it.cavallium.data.generator.plugin;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class VersionChangeChecker {
|
||||
|
||||
private final Set<String> changedTypes;
|
||||
|
||||
public VersionChangeChecker(Set<String> changedTypes) {
|
||||
this.changedTypes = changedTypes;
|
||||
}
|
||||
|
||||
public boolean checkChanged(String name) {
|
||||
return changedTypes.contains(name);
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package it.cavallium.data.generator.plugin;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@ -8,6 +10,29 @@ public class VersionConfiguration {
|
||||
public String previousVersion;
|
||||
public DetailsConfiguration details;
|
||||
public List<VersionTransformation> transformations;
|
||||
/**
|
||||
* <pre>
|
||||
* Type 1: v1
|
||||
* Type 2: v4
|
||||
* Type 3: v2
|
||||
* ...
|
||||
* </pre>
|
||||
*/
|
||||
public Object2IntMap<String> typeVersions;
|
||||
/**
|
||||
* <pre>
|
||||
* - Type 1
|
||||
* |_Dependent type 1
|
||||
* |_Dependent type 2
|
||||
* |_Dependent type ...
|
||||
*
|
||||
* - Type 2
|
||||
* |_Dependent type 1
|
||||
* |_Dependent type 2
|
||||
* |_Dependent type ...
|
||||
* </pre>
|
||||
*/
|
||||
public Object2ObjectMap<String, List<String>> dependentTypes;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
@ -0,0 +1,18 @@
|
||||
package it.cavallium.data.generator.plugin;
|
||||
|
||||
public record VersionedType(String type, int version) {
|
||||
|
||||
public VersionedType withVersion(int version) {
|
||||
if (version == this.version) {
|
||||
return this;
|
||||
}
|
||||
return new VersionedType(type, version);
|
||||
}
|
||||
|
||||
public VersionedType withVersionIfChanged(int version, VersionChangeChecker versionChangeChecker) {
|
||||
if (versionChangeChecker.checkChanged(this.type)) {
|
||||
return withVersion(version);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user