diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedType.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedType.java new file mode 100644 index 0000000..e72adfd --- /dev/null +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedType.java @@ -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 getDependencies(); + + /** + * Get all types that require this type + */ + Stream getDependents(); + + final class ComputedBaseType implements VersionedComputedType { + + private final VersionedType type; + private final String stringRepresenter; + + private final LinkedHashMap data; + private LinkedHashMap computedData; + private final ComputedTypeSupplier computedTypeSupplier; + + public ComputedBaseType(VersionedType type, + String stringRepresenter, + LinkedHashMap 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(); + 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 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 getDependencies() { + return this.data.values().stream().map(computedTypeSupplier::get); + } + + @Override + public Stream 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 getDependencies() { + return Stream.of(); + } + + @Override + public Stream 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 getDependencies() { + return Stream.of(child()); + } + + @Override + public Stream getDependents() { + return computedTypeSupplier.getDependents(new VersionedType(getName(), 0)); + } + } + + final class ComputedSuperType implements VersionedComputedType { + + private final VersionedType type; + private final List subTypes; + + private List computedSubTypes; + private final ComputedTypeSupplier computedTypeSupplier; + + public ComputedSuperType(VersionedType type, + List 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 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 getDependencies() { + return subTypes().stream(); + } + + @Override + public Stream 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 getDependencies() { + return Stream.of(child()); + } + + @Override + public Stream 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 getDependencies() { + return Stream.of(); + } + + @Override + public Stream getDependents() { + return computedTypeSupplier.getDependents(new VersionedType(getName(), 0)); + } + + public static List get(ComputedTypeSupplier computedTypeSupplier) { + return Stream.of("String", + "boolean", + "short", + "char", + "int", + "long", + "float", + "double", + "byte", + "Int52").map(name -> new ComputedNativeType(name, computedTypeSupplier)).toList(); + } + } +} diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeSupplier.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeSupplier.java new file mode 100644 index 0000000..eebf72f --- /dev/null +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeSupplier.java @@ -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> computedTypeMap; + private final Int2ObjectMap>> computedTypeDependentsCacheMap = new Int2ObjectOpenHashMap<>(); + + public ComputedTypeSupplier(Int2ObjectMap> 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 getDependencies(VersionedType type) { + return computedTypeMap.get(type.version()).get(type.type()).getDependencies(); + } + + public Stream 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(); + } + } +} diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/CustomTypesConfiguration.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/CustomTypesConfiguration.java index 7cd1812..e28ecc2 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/CustomTypesConfiguration.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/CustomTypesConfiguration.java @@ -31,6 +31,10 @@ public final class CustomTypesConfiguration { } } + public String getJavaClassString() { + return javaClass; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/DataModel.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/DataModel.java index 5e97b58..9f47abc 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/DataModel.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/DataModel.java @@ -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> classConfig; private final int hash; private final Map interfacesData; private final Int2ObjectMap versions; private final Map> superTypes; private final Map customTypes; + private final Int2ObjectMap> computedTypes; public DataModel(int hash, String currentVersionKey, @@ -95,7 +105,7 @@ public class DataModel { // Build versions sequence List rawVersionsSequence = new ArrayList<>(); int versionsCount = 0; - Int2ObjectMap versionToName = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap versionToName = new Int2ObjectLinkedOpenHashMap<>(); Object2IntMap 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 versions = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap versions = new Int2ObjectLinkedOpenHashMap<>(); rawVersions.forEach((k, v) -> versions.put(nameToVersion.getInt(k), new ParsedVersion(v))); - Int2ObjectMap> computedClassConfig = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap> 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> 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 versionBaseTypes = computedClassConfig.get(versionIndexF).entrySet().stream() + .map(e -> { + var data = new LinkedHashMap(); + 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 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 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 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 data, String key, String value, int index) { @@ -429,4 +588,8 @@ public class DataModel { public Map getCustomTypes() { return customTypes; } + + public Int2ObjectMap> getComputedTypes() { + return computedTypes; + } } diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ParsedClass.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ParsedClass.java index 4078770..659890f 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ParsedClass.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ParsedClass.java @@ -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 data; + public boolean changed; public ParsedClass(ClassConfiguration baseTypesData) { this.stringRepresenter = baseTypesData.stringRepresenter; diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/VersionChangeChecker.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/VersionChangeChecker.java new file mode 100644 index 0000000..5c7d448 --- /dev/null +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/VersionChangeChecker.java @@ -0,0 +1,16 @@ +package it.cavallium.data.generator.plugin; + +import java.util.Set; + +public class VersionChangeChecker { + + private final Set changedTypes; + + public VersionChangeChecker(Set changedTypes) { + this.changedTypes = changedTypes; + } + + public boolean checkChanged(String name) { + return changedTypes.contains(name); + } +} diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/VersionConfiguration.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/VersionConfiguration.java index d22d2b5..8cda67a 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/VersionConfiguration.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/VersionConfiguration.java @@ -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 transformations; + /** + *
+	 * Type 1: v1
+	 * Type 2: v4
+	 * Type 3: v2
+	 * ...
+	 * 
+ */ + public Object2IntMap typeVersions; + /** + *
+	 * - Type 1
+	 *   |_Dependent type 1
+	 *   |_Dependent type 2
+	 *   |_Dependent type ...
+	 *
+	 * - Type 2
+	 *   |_Dependent type 1
+	 *   |_Dependent type 2
+	 *   |_Dependent type ...
+	 * 
+ */ + public Object2ObjectMap> dependentTypes; @Override public boolean equals(Object o) { diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/VersionedType.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/VersionedType.java new file mode 100644 index 0000000..244c7c5 --- /dev/null +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/VersionedType.java @@ -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; + } +}