Compute all types

This commit is contained in:
Andrea Cavalli 2023-01-19 01:36:57 +01:00
parent f6fe7017c7
commit 4485dd675f
8 changed files with 765 additions and 8 deletions

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -31,6 +31,10 @@ public final class CustomTypesConfiguration {
}
}
public String getJavaClassString() {
return javaClass;
}
@Override
public boolean equals(Object o) {
if (this == o) {

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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;
}
}