From cf016012e62118bc75e777c31878bc4250a39886 Mon Sep 17 00:00:00 2001 From: Wyrdix Date: Thu, 9 Jul 2026 23:53:24 +0200 Subject: [PATCH 1/4] Add array converter in ValueSerializer.java --- src/plm/core/ValueSerializer.java | 77 ++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/src/plm/core/ValueSerializer.java b/src/plm/core/ValueSerializer.java index ea6247d25..d8b582307 100644 --- a/src/plm/core/ValueSerializer.java +++ b/src/plm/core/ValueSerializer.java @@ -1,8 +1,70 @@ package plm.core; +import java.lang.reflect.Array; +import java.util.Arrays; import java.util.Vector; public class ValueSerializer { + + @SuppressWarnings("unchecked") + public static T[] toArrayOfType(Object original, Class newType) { + + if(original instanceof int[]) { + int[] array = (int[]) original; + Integer[] newArray = new Integer[array.length]; + for(int i = 0; i < array.length; i++) + newArray[i] = array[i]; + return toArrayOfType(newArray, newType); + } + + if(original instanceof double[]) { + double[] array = (double[]) original; + Double[] newArray = new Double[array.length]; + for(int i = 0; i < array.length; i++) + newArray[i] = array[i]; + return toArrayOfType(newArray, newType); + } + + if(original instanceof boolean[]) { + boolean[] array = (boolean[]) original; + Boolean[] newArray = new Boolean[array.length]; + for(int i = 0; i < array.length; i++) + newArray[i] = array[i]; + return toArrayOfType(newArray, newType); + } + + if(newType.arrayType().isInstance(original)) return (T[]) original; + Object[] array = (Object[]) original; + + + Object o = Array.newInstance(newType, array.length); + T[] newArray = (T[]) o; + for(int i = 0; i < array.length; i++) + newArray[i] = (T) array[i]; + return newArray; + } + + public static int[] toPrimitive(Integer[] array){ + int[] newArray = new int[array.length]; + for(int i = 0; i < array.length; i++) + newArray[i] = array[i]; + return newArray; + } + + public static double[] toPrimitive(Double[] array){ + double[] newArray = new double[array.length]; + for(int i = 0; i < array.length; i++) + newArray[i] = array[i]; + return newArray; + } + + public static boolean[] toPrimitive(Boolean[] array){ + boolean[] newArray = new boolean[array.length]; + for(int i = 0; i < array.length; i++) + newArray[i] = array[i]; + return newArray; + } + /* --- Serialization logic --- */ public static String serialize(Object o) { @@ -15,16 +77,19 @@ public static String serialize(Object o) sb.append('['); // Primitive types must be handled explicitely, as int cannot be casted to Object for a generic case. if (o.getClass().getComponentType().equals(Integer.TYPE)) { + assert o instanceof int[]; int[] a = (int[])o; sb.append(a.length); for (int i : a) sb.append(":i" + i); } else if (o.getClass().getComponentType().equals(Double.TYPE)) { + assert o instanceof double[]; double[] a = (double[])o; sb.append(a.length); for (double i : a) sb.append(":f" + i); } else if (o.getClass().getComponentType().equals(Boolean.TYPE)) { + assert o instanceof boolean[]; boolean[] a = (boolean[])o; sb.append(a.length); for (boolean b : a) @@ -85,7 +150,7 @@ private static class Parser { Object parse() { if (pos >= input.length()) { - throw new IllegalArgumentException("Unexpected end of input at position " + pos); + throw new IllegalArgumentException("Unexpected end of input at position " + pos+" in "+input); } char c = input.charAt(pos); @@ -108,7 +173,7 @@ private Object[] parseArray() int colonIdx = input.indexOf(':', pos); if (colonIdx == -1) { - throw new IllegalArgumentException("Expected ':' after array length at position " + pos); + throw new IllegalArgumentException("Expected ':' after array length at position " + pos+" in "+input); } int len = Integer.parseInt(input.substring(pos, colonIdx)); @@ -119,14 +184,14 @@ private Object[] parseArray() arr[i] = parse(); if (i < len - 1) { if (input.charAt(pos) != ':') { - throw new IllegalArgumentException("Expected ':' between array elements at position " + pos); + throw new IllegalArgumentException("Expected ':' between array elements at position " + pos+" in "+input); } pos++; // Skip ':' } } if (pos >= input.length() || input.charAt(pos) != ']') { - throw new IllegalArgumentException("Expected ']' at end of array at position " + pos); + throw new IllegalArgumentException("Expected ']' at end of array at position " + pos+" in "+input); } pos++; // Skip ']' return arr; @@ -149,7 +214,7 @@ private String parseString() pos++; } } - throw new IllegalArgumentException("Unterminated string starting at position " + (pos - sb.length() - 1)); + throw new IllegalArgumentException("Unterminated string starting at position " + (pos - sb.length() - 1)+" in "+input); } private Object parsePrimitive() @@ -170,7 +235,7 @@ private Object parsePrimitive() case 'f': return Double.parseDouble(val); default: // Fallback if format string is exhausted or mismatched - throw new IllegalArgumentException("Parse error: Invalid type hint '" + typeHint + "' at position " + start + " in input \"" + input + "\""); + throw new IllegalArgumentException("Parse error: Invalid type hint '" + typeHint + "' at position " + start + " in input \"" + input + "\""+" in "+input); } } catch (NumberFormatException e) { throw new IllegalArgumentException(e); From f9b1da059d4dede0e7740a2dafe811b1ebe491c5 Mon Sep 17 00:00:00 2001 From: Wyrdix Date: Thu, 9 Jul 2026 23:53:46 +0200 Subject: [PATCH 2/4] Use of the array converter in all lessons instead of simple cast --- src/lessons/recursion/cons/AllDifferentEntity.java | 2 +- src/lessons/recursion/cons/ButLastEntity.java | 2 +- src/lessons/recursion/cons/ButNfirstEntity.java | 7 +++---- src/lessons/recursion/cons/ButNlastEntity.java | 2 +- src/lessons/recursion/cons/ConcatEntity.java | 2 +- src/lessons/recursion/cons/IncreasingEntity.java | 2 +- src/lessons/recursion/cons/IsMemberEntity.java | 2 +- src/lessons/recursion/cons/LastEntity.java | 2 +- src/lessons/recursion/cons/LengthEntity.java | 2 +- src/lessons/recursion/cons/MinEntity.java | 2 +- src/lessons/recursion/cons/NfirstEntity.java | 2 +- src/lessons/recursion/cons/NlastEntity.java | 2 +- src/lessons/recursion/cons/NthEntity.java | 2 +- src/lessons/recursion/cons/OccurrenceEntity.java | 2 +- src/lessons/recursion/cons/PlusOneEntity.java | 2 +- src/lessons/recursion/cons/RemoveEntity.java | 2 +- src/lessons/recursion/cons/ReverseEntity.java | 2 +- src/lessons/recursion/lego/tree/TreeEntity.java | 2 +- src/lessons/sort/basic/comb/AlgCombSort11Entity.java | 2 +- src/lessons/sort/basic/comb/AlgCombSortEntity.java | 2 +- src/lessons/welcome/array/array123/Array123Entity.java | 2 +- src/lessons/welcome/array/array667/Array667Entity.java | 2 +- .../welcome/array/arraycount9/ArrayCount9Entity.java | 2 +- .../welcome/array/arrayfront9/ArrayFront9Entity.java | 2 +- src/lessons/welcome/array/has271/Has271Entity.java | 2 +- src/lessons/welcome/array/island/IslandEntity.java | 2 +- src/lessons/welcome/array/notriples/NoTriplesEntity.java | 2 +- src/lessons/welcome/array/search/AverageValueEntity.java | 2 +- src/lessons/welcome/array/search/ExtremaEntity.java | 2 +- .../welcome/array/search/IndexOfMaxValueEntity.java | 2 +- src/lessons/welcome/array/search/IndexOfValueEntity.java | 3 ++- src/lessons/welcome/array/search/MaxValueEntity.java | 2 +- .../welcome/array/search/OccurrenceOfValueEntity.java | 2 +- src/lessons/welcome/array/search/SecondMaxValueEntity.java | 2 +- 34 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/lessons/recursion/cons/AllDifferentEntity.java b/src/lessons/recursion/cons/AllDifferentEntity.java index 907ec11a5..ab52a4899 100644 --- a/src/lessons/recursion/cons/AllDifferentEntity.java +++ b/src/lessons/recursion/cons/AllDifferentEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(allDifferent(RecList.fromArray((int[])param[0])))); + setTestResult(i, serialize(allDifferent(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); } } diff --git a/src/lessons/recursion/cons/ButLastEntity.java b/src/lessons/recursion/cons/ButLastEntity.java index 305cfd107..b002adf2e 100644 --- a/src/lessons/recursion/cons/ButLastEntity.java +++ b/src/lessons/recursion/cons/ButLastEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(butLast(RecList.fromArray((int[])param[0])))); + setTestResult(i, serialize(butLast(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); } } diff --git a/src/lessons/recursion/cons/ButNfirstEntity.java b/src/lessons/recursion/cons/ButNfirstEntity.java index b4bb69e85..5fd24fff6 100644 --- a/src/lessons/recursion/cons/ButNfirstEntity.java +++ b/src/lessons/recursion/cons/ButNfirstEntity.java @@ -1,11 +1,10 @@ package lessons.recursion.cons; -import static plm.core.ValueSerializer.deserialize; -import static plm.core.ValueSerializer.serialize; - import lessons.recursion.cons.universe.ConsEntity; import lessons.recursion.cons.universe.RecList; +import static plm.core.ValueSerializer.*; + public class ButNfirstEntity extends ConsEntity { public void run() @@ -13,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(butNfirst(RecList.fromArray((int[])param[0]), (Integer)param[1]))); + setTestResult(i, serialize(butNfirst(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/ButNlastEntity.java b/src/lessons/recursion/cons/ButNlastEntity.java index f7e72f87b..90bc02bf5 100644 --- a/src/lessons/recursion/cons/ButNlastEntity.java +++ b/src/lessons/recursion/cons/ButNlastEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(butNlast(RecList.fromArray((int[])param[0]), (Integer)param[1]))); + setTestResult(i, serialize(butNlast(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/ConcatEntity.java b/src/lessons/recursion/cons/ConcatEntity.java index 4ca92f9e1..73668622c 100644 --- a/src/lessons/recursion/cons/ConcatEntity.java +++ b/src/lessons/recursion/cons/ConcatEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(concat(RecList.fromArray((int[])param[0]), RecList.fromArray((int[])param[1])))); + setTestResult(i, serialize(concat(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), RecList.fromArray(toPrimitive(toArrayOfType(param[1], Integer.class)))))); } } diff --git a/src/lessons/recursion/cons/IncreasingEntity.java b/src/lessons/recursion/cons/IncreasingEntity.java index 78568a57f..fc608487a 100644 --- a/src/lessons/recursion/cons/IncreasingEntity.java +++ b/src/lessons/recursion/cons/IncreasingEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(increasing(RecList.fromArray((int[])param[0])))); + setTestResult(i, serialize(increasing(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); } } diff --git a/src/lessons/recursion/cons/IsMemberEntity.java b/src/lessons/recursion/cons/IsMemberEntity.java index aa60e0c82..629405c52 100644 --- a/src/lessons/recursion/cons/IsMemberEntity.java +++ b/src/lessons/recursion/cons/IsMemberEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(isMember(RecList.fromArray((int[])param[0]), (Integer)param[1]))); + setTestResult(i, serialize(isMember(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/LastEntity.java b/src/lessons/recursion/cons/LastEntity.java index d8012b387..14e141946 100644 --- a/src/lessons/recursion/cons/LastEntity.java +++ b/src/lessons/recursion/cons/LastEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(last(RecList.fromArray((int[])param[0])))); + setTestResult(i, serialize(last(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); } } diff --git a/src/lessons/recursion/cons/LengthEntity.java b/src/lessons/recursion/cons/LengthEntity.java index f9df2e1f4..83d9ed091 100644 --- a/src/lessons/recursion/cons/LengthEntity.java +++ b/src/lessons/recursion/cons/LengthEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(length(RecList.fromArray((int[])param[0])))); + setTestResult(i, serialize(length(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); } } diff --git a/src/lessons/recursion/cons/MinEntity.java b/src/lessons/recursion/cons/MinEntity.java index e0ff348bc..a89829f7d 100644 --- a/src/lessons/recursion/cons/MinEntity.java +++ b/src/lessons/recursion/cons/MinEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(min(RecList.fromArray((int[])param[0])))); + setTestResult(i, serialize(min(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); } } diff --git a/src/lessons/recursion/cons/NfirstEntity.java b/src/lessons/recursion/cons/NfirstEntity.java index 27a3f460e..7743dc18b 100644 --- a/src/lessons/recursion/cons/NfirstEntity.java +++ b/src/lessons/recursion/cons/NfirstEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(nfirst(RecList.fromArray((int[])param[0]), (Integer)param[1]))); + setTestResult(i, serialize(nfirst(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/NlastEntity.java b/src/lessons/recursion/cons/NlastEntity.java index 8d52c3953..ffb9946db 100644 --- a/src/lessons/recursion/cons/NlastEntity.java +++ b/src/lessons/recursion/cons/NlastEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(nlast(RecList.fromArray((int[])param[0]), (Integer)param[1]))); + setTestResult(i, serialize(nlast(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/NthEntity.java b/src/lessons/recursion/cons/NthEntity.java index d5772acc0..11179e5b9 100644 --- a/src/lessons/recursion/cons/NthEntity.java +++ b/src/lessons/recursion/cons/NthEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(nth(RecList.fromArray((int[])param[0]), (Integer)param[1]))); + setTestResult(i, serialize(nth(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/OccurrenceEntity.java b/src/lessons/recursion/cons/OccurrenceEntity.java index 45836b658..0975b5d58 100644 --- a/src/lessons/recursion/cons/OccurrenceEntity.java +++ b/src/lessons/recursion/cons/OccurrenceEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(occurences(RecList.fromArray((int[])param[0]), (Integer)param[1]))); + setTestResult(i, serialize(occurences(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/PlusOneEntity.java b/src/lessons/recursion/cons/PlusOneEntity.java index f9c044918..10c3144af 100644 --- a/src/lessons/recursion/cons/PlusOneEntity.java +++ b/src/lessons/recursion/cons/PlusOneEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(plusOne(RecList.fromArray((int[])param[0])))); + setTestResult(i, serialize(plusOne(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); } } diff --git a/src/lessons/recursion/cons/RemoveEntity.java b/src/lessons/recursion/cons/RemoveEntity.java index aa07a715f..9b75a515b 100644 --- a/src/lessons/recursion/cons/RemoveEntity.java +++ b/src/lessons/recursion/cons/RemoveEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(remove(RecList.fromArray((int[])param[0]), (Integer)param[1]))); + setTestResult(i, serialize(remove(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/ReverseEntity.java b/src/lessons/recursion/cons/ReverseEntity.java index 85b8a5a67..84a74a4b8 100644 --- a/src/lessons/recursion/cons/ReverseEntity.java +++ b/src/lessons/recursion/cons/ReverseEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(reverse(RecList.fromArray((int[])param[0])))); + setTestResult(i, serialize(reverse(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); } } diff --git a/src/lessons/recursion/lego/tree/TreeEntity.java b/src/lessons/recursion/lego/tree/TreeEntity.java index d69c9641f..29e10b20a 100644 --- a/src/lessons/recursion/lego/tree/TreeEntity.java +++ b/src/lessons/recursion/lego/tree/TreeEntity.java @@ -28,7 +28,7 @@ public void setPos(int i,int j) { Color.lightGray, Color.gray, Color.darkGray, Color.black, Color.red}; @Primitive(308) - private void current(int v) { + public void current(int v) { if (v>=colors.length || v < 0) setColor(colors[colors.length -1]); setColor(colors[v]); diff --git a/src/lessons/sort/basic/comb/AlgCombSort11Entity.java b/src/lessons/sort/basic/comb/AlgCombSort11Entity.java index 7f12771b6..57f5db857 100644 --- a/src/lessons/sort/basic/comb/AlgCombSort11Entity.java +++ b/src/lessons/sort/basic/comb/AlgCombSort11Entity.java @@ -15,7 +15,7 @@ public void combSort11() { boolean swapped; do { if (gap>1) { - gap /= 1.3; + gap = (int) (gap / 1.3); if (gap == 10 || gap == 9) gap = 11; } diff --git a/src/lessons/sort/basic/comb/AlgCombSortEntity.java b/src/lessons/sort/basic/comb/AlgCombSortEntity.java index 670de741d..2b4ad3ce6 100644 --- a/src/lessons/sort/basic/comb/AlgCombSortEntity.java +++ b/src/lessons/sort/basic/comb/AlgCombSortEntity.java @@ -15,7 +15,7 @@ public void combSort() { boolean swapped; do { if (gap>1) - gap /= 1.3; + gap = (int) (gap / 1.3); swapped = false; for (int i=0; i+gap Date: Thu, 9 Jul 2026 23:54:03 +0200 Subject: [PATCH 3/4] Use the right language in ExerciseTemplated error message --- src/plm/core/model/lesson/ExerciseTemplated.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plm/core/model/lesson/ExerciseTemplated.java b/src/plm/core/model/lesson/ExerciseTemplated.java index 7f6d13a20..31051b509 100644 --- a/src/plm/core/model/lesson/ExerciseTemplated.java +++ b/src/plm/core/model/lesson/ExerciseTemplated.java @@ -411,7 +411,7 @@ public void run() { compileAll(Game.getInstance().getOutputWriter(), StudentOrCorrection.CORRECTION); } catch (PLMCompilerException e) { System.err.println("Severe error: the correction of exercise " + id + - " cannot be compiled in C. Please go fix your PLM."); + " cannot be compiled in "+Game.getInstance().getProgrammingLanguage().getLang()+". Please go fix your PLM."); e.printStackTrace(); Game.getInstance().setState(Game.GameState.COMPILATION_ENDED); Game.getInstance().setState(Game.GameState.EXECUTION_ENDED); From 9b2b7fdc4c43196d01892d519123284339953777 Mon Sep 17 00:00:00 2001 From: Wyrdix Date: Fri, 10 Jul 2026 15:16:02 +0200 Subject: [PATCH 4/4] Change the serializer/deserializer to specify array type and enable primitive array deserialization --- .../recursion/cons/AllDifferentEntity.java | 2 +- src/lessons/recursion/cons/ButLastEntity.java | 2 +- .../recursion/cons/ButNfirstEntity.java | 2 +- .../recursion/cons/ButNlastEntity.java | 2 +- src/lessons/recursion/cons/ConcatEntity.java | 2 +- .../recursion/cons/IncreasingEntity.java | 2 +- .../recursion/cons/IsMemberEntity.java | 2 +- src/lessons/recursion/cons/LastEntity.java | 2 +- src/lessons/recursion/cons/LengthEntity.java | 2 +- src/lessons/recursion/cons/MinEntity.java | 2 +- src/lessons/recursion/cons/NfirstEntity.java | 2 +- src/lessons/recursion/cons/NlastEntity.java | 2 +- src/lessons/recursion/cons/NthEntity.java | 2 +- .../recursion/cons/OccurrenceEntity.java | 2 +- src/lessons/recursion/cons/PlusOneEntity.java | 2 +- src/lessons/recursion/cons/RemoveEntity.java | 2 +- src/lessons/recursion/cons/ReverseEntity.java | 2 +- .../array/array123/Array123Entity.java | 2 +- .../array/array667/Array667Entity.java | 2 +- .../array/arraycount9/ArrayCount9Entity.java | 2 +- .../array/arrayfront9/ArrayFront9Entity.java | 2 +- .../welcome/array/has271/Has271Entity.java | 2 +- .../welcome/array/island/IslandEntity.java | 2 +- .../array/notriples/NoTriplesEntity.java | 2 +- .../array/search/AverageValueEntity.java | 2 +- .../welcome/array/search/ExtremaEntity.java | 2 +- .../array/search/IndexOfMaxValueEntity.java | 2 +- .../array/search/IndexOfValueEntity.java | 2 +- .../welcome/array/search/MaxValueEntity.java | 2 +- .../array/search/OccurrenceOfValueEntity.java | 2 +- .../array/search/SecondMaxValueEntity.java | 2 +- src/plm/core/ValueSerializer.java | 489 ++++++++++-------- src/plm/core/ValueSerializerTest.java | 14 +- 33 files changed, 300 insertions(+), 265 deletions(-) diff --git a/src/lessons/recursion/cons/AllDifferentEntity.java b/src/lessons/recursion/cons/AllDifferentEntity.java index ab52a4899..10bcb89cb 100644 --- a/src/lessons/recursion/cons/AllDifferentEntity.java +++ b/src/lessons/recursion/cons/AllDifferentEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(allDifferent(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); + setTestResult(i, serialize(allDifferent(RecList.fromArray((int[]) param[0])))); } } diff --git a/src/lessons/recursion/cons/ButLastEntity.java b/src/lessons/recursion/cons/ButLastEntity.java index b002adf2e..b503c8322 100644 --- a/src/lessons/recursion/cons/ButLastEntity.java +++ b/src/lessons/recursion/cons/ButLastEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(butLast(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); + setTestResult(i, serialize(butLast(RecList.fromArray((int[]) param[0])))); } } diff --git a/src/lessons/recursion/cons/ButNfirstEntity.java b/src/lessons/recursion/cons/ButNfirstEntity.java index 5fd24fff6..14c9d0639 100644 --- a/src/lessons/recursion/cons/ButNfirstEntity.java +++ b/src/lessons/recursion/cons/ButNfirstEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(butNfirst(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); + setTestResult(i, serialize(butNfirst(RecList.fromArray((int[]) param[0]), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/ButNlastEntity.java b/src/lessons/recursion/cons/ButNlastEntity.java index 90bc02bf5..c36519a64 100644 --- a/src/lessons/recursion/cons/ButNlastEntity.java +++ b/src/lessons/recursion/cons/ButNlastEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(butNlast(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); + setTestResult(i, serialize(butNlast(RecList.fromArray((int[]) param[0]), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/ConcatEntity.java b/src/lessons/recursion/cons/ConcatEntity.java index 73668622c..2b5d14232 100644 --- a/src/lessons/recursion/cons/ConcatEntity.java +++ b/src/lessons/recursion/cons/ConcatEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(concat(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), RecList.fromArray(toPrimitive(toArrayOfType(param[1], Integer.class)))))); + setTestResult(i, serialize(concat(RecList.fromArray((int[]) param[0]), RecList.fromArray((int[]) param[1])))); } } diff --git a/src/lessons/recursion/cons/IncreasingEntity.java b/src/lessons/recursion/cons/IncreasingEntity.java index fc608487a..ecc753cfc 100644 --- a/src/lessons/recursion/cons/IncreasingEntity.java +++ b/src/lessons/recursion/cons/IncreasingEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(increasing(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); + setTestResult(i, serialize(increasing(RecList.fromArray((int[]) param[0])))); } } diff --git a/src/lessons/recursion/cons/IsMemberEntity.java b/src/lessons/recursion/cons/IsMemberEntity.java index 629405c52..73b5ca718 100644 --- a/src/lessons/recursion/cons/IsMemberEntity.java +++ b/src/lessons/recursion/cons/IsMemberEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(isMember(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); + setTestResult(i, serialize(isMember(RecList.fromArray((int[]) param[0]), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/LastEntity.java b/src/lessons/recursion/cons/LastEntity.java index 14e141946..1cd3600a7 100644 --- a/src/lessons/recursion/cons/LastEntity.java +++ b/src/lessons/recursion/cons/LastEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(last(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); + setTestResult(i, serialize(last(RecList.fromArray((int[]) param[0])))); } } diff --git a/src/lessons/recursion/cons/LengthEntity.java b/src/lessons/recursion/cons/LengthEntity.java index 83d9ed091..63c36165f 100644 --- a/src/lessons/recursion/cons/LengthEntity.java +++ b/src/lessons/recursion/cons/LengthEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(length(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); + setTestResult(i, serialize(length(RecList.fromArray((int[]) param[0])))); } } diff --git a/src/lessons/recursion/cons/MinEntity.java b/src/lessons/recursion/cons/MinEntity.java index a89829f7d..470645e6c 100644 --- a/src/lessons/recursion/cons/MinEntity.java +++ b/src/lessons/recursion/cons/MinEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(min(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); + setTestResult(i, serialize(min(RecList.fromArray((int[]) param[0])))); } } diff --git a/src/lessons/recursion/cons/NfirstEntity.java b/src/lessons/recursion/cons/NfirstEntity.java index 7743dc18b..cfbd89fff 100644 --- a/src/lessons/recursion/cons/NfirstEntity.java +++ b/src/lessons/recursion/cons/NfirstEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(nfirst(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); + setTestResult(i, serialize(nfirst(RecList.fromArray((int[]) param[0]), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/NlastEntity.java b/src/lessons/recursion/cons/NlastEntity.java index ffb9946db..9506e8490 100644 --- a/src/lessons/recursion/cons/NlastEntity.java +++ b/src/lessons/recursion/cons/NlastEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(nlast(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); + setTestResult(i, serialize(nlast(RecList.fromArray((int[]) param[0]), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/NthEntity.java b/src/lessons/recursion/cons/NthEntity.java index 11179e5b9..84cabb5c9 100644 --- a/src/lessons/recursion/cons/NthEntity.java +++ b/src/lessons/recursion/cons/NthEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(nth(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); + setTestResult(i, serialize(nth(RecList.fromArray((int[]) param[0]), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/OccurrenceEntity.java b/src/lessons/recursion/cons/OccurrenceEntity.java index 0975b5d58..5f1fc361e 100644 --- a/src/lessons/recursion/cons/OccurrenceEntity.java +++ b/src/lessons/recursion/cons/OccurrenceEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(occurences(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); + setTestResult(i, serialize(occurences(RecList.fromArray((int[]) param[0]), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/PlusOneEntity.java b/src/lessons/recursion/cons/PlusOneEntity.java index 10c3144af..c0729476d 100644 --- a/src/lessons/recursion/cons/PlusOneEntity.java +++ b/src/lessons/recursion/cons/PlusOneEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(plusOne(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); + setTestResult(i, serialize(plusOne(RecList.fromArray((int[]) param[0])))); } } diff --git a/src/lessons/recursion/cons/RemoveEntity.java b/src/lessons/recursion/cons/RemoveEntity.java index 9b75a515b..b5f9c3049 100644 --- a/src/lessons/recursion/cons/RemoveEntity.java +++ b/src/lessons/recursion/cons/RemoveEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(remove(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class))), (Integer)param[1]))); + setTestResult(i, serialize(remove(RecList.fromArray((int[]) param[0]), (Integer)param[1]))); } } diff --git a/src/lessons/recursion/cons/ReverseEntity.java b/src/lessons/recursion/cons/ReverseEntity.java index 84a74a4b8..03a6b081c 100644 --- a/src/lessons/recursion/cons/ReverseEntity.java +++ b/src/lessons/recursion/cons/ReverseEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(reverse(RecList.fromArray(toPrimitive(toArrayOfType(param[0], Integer.class)))))); + setTestResult(i, serialize(reverse(RecList.fromArray((int[]) param[0])))); } } diff --git a/src/lessons/welcome/array/array123/Array123Entity.java b/src/lessons/welcome/array/array123/Array123Entity.java index 6b3c0fd87..b018eee35 100644 --- a/src/lessons/welcome/array/array123/Array123Entity.java +++ b/src/lessons/welcome/array/array123/Array123Entity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(array123(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(array123((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/array667/Array667Entity.java b/src/lessons/welcome/array/array667/Array667Entity.java index 644e573fb..45a78c0b0 100644 --- a/src/lessons/welcome/array/array667/Array667Entity.java +++ b/src/lessons/welcome/array/array667/Array667Entity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(array667(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(array667((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/arraycount9/ArrayCount9Entity.java b/src/lessons/welcome/array/arraycount9/ArrayCount9Entity.java index c14ae5d6d..d0638522d 100644 --- a/src/lessons/welcome/array/arraycount9/ArrayCount9Entity.java +++ b/src/lessons/welcome/array/arraycount9/ArrayCount9Entity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(arrayCount9(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(arrayCount9((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/arrayfront9/ArrayFront9Entity.java b/src/lessons/welcome/array/arrayfront9/ArrayFront9Entity.java index b42195c71..63708d24a 100644 --- a/src/lessons/welcome/array/arrayfront9/ArrayFront9Entity.java +++ b/src/lessons/welcome/array/arrayfront9/ArrayFront9Entity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(arrayFront9(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(arrayFront9((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/has271/Has271Entity.java b/src/lessons/welcome/array/has271/Has271Entity.java index 3b2e2413c..d62872e6e 100644 --- a/src/lessons/welcome/array/has271/Has271Entity.java +++ b/src/lessons/welcome/array/has271/Has271Entity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(has271(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(has271((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/island/IslandEntity.java b/src/lessons/welcome/array/island/IslandEntity.java index 967924c23..3b8544f08 100644 --- a/src/lessons/welcome/array/island/IslandEntity.java +++ b/src/lessons/welcome/array/island/IslandEntity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(island(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(island((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/notriples/NoTriplesEntity.java b/src/lessons/welcome/array/notriples/NoTriplesEntity.java index aa980a4be..9425026ec 100644 --- a/src/lessons/welcome/array/notriples/NoTriplesEntity.java +++ b/src/lessons/welcome/array/notriples/NoTriplesEntity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(noTriples(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(noTriples((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/search/AverageValueEntity.java b/src/lessons/welcome/array/search/AverageValueEntity.java index dc2125fe7..574bc09bc 100644 --- a/src/lessons/welcome/array/search/AverageValueEntity.java +++ b/src/lessons/welcome/array/search/AverageValueEntity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(averageValue(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(averageValue((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/search/ExtremaEntity.java b/src/lessons/welcome/array/search/ExtremaEntity.java index 7ebb716c1..14f88f684 100644 --- a/src/lessons/welcome/array/search/ExtremaEntity.java +++ b/src/lessons/welcome/array/search/ExtremaEntity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(extrema(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(extrema((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/search/IndexOfMaxValueEntity.java b/src/lessons/welcome/array/search/IndexOfMaxValueEntity.java index 5861658e0..3358b87b5 100644 --- a/src/lessons/welcome/array/search/IndexOfMaxValueEntity.java +++ b/src/lessons/welcome/array/search/IndexOfMaxValueEntity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(indexOfMaximum(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(indexOfMaximum((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/search/IndexOfValueEntity.java b/src/lessons/welcome/array/search/IndexOfValueEntity.java index 203defd64..4cf1143be 100644 --- a/src/lessons/welcome/array/search/IndexOfValueEntity.java +++ b/src/lessons/welcome/array/search/IndexOfValueEntity.java @@ -12,7 +12,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(indexOf(toPrimitive(toArrayOfType(param[0], Integer.class)), (Integer)param[1]))); + setTestResult(i, serialize(indexOf((int[]) param[0], (Integer)param[1]))); } } diff --git a/src/lessons/welcome/array/search/MaxValueEntity.java b/src/lessons/welcome/array/search/MaxValueEntity.java index 53289a4fe..ea5f94efd 100644 --- a/src/lessons/welcome/array/search/MaxValueEntity.java +++ b/src/lessons/welcome/array/search/MaxValueEntity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(maxValue(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(maxValue((int[]) param[0]))); } } diff --git a/src/lessons/welcome/array/search/OccurrenceOfValueEntity.java b/src/lessons/welcome/array/search/OccurrenceOfValueEntity.java index 449e88797..e97f9d643 100644 --- a/src/lessons/welcome/array/search/OccurrenceOfValueEntity.java +++ b/src/lessons/welcome/array/search/OccurrenceOfValueEntity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(occurrences(toPrimitive(toArrayOfType(param[0], Integer.class)), (Integer)param[1]))); + setTestResult(i, serialize(occurrences((int[]) param[0], (Integer)param[1]))); } } diff --git a/src/lessons/welcome/array/search/SecondMaxValueEntity.java b/src/lessons/welcome/array/search/SecondMaxValueEntity.java index 0715764bc..87921959e 100644 --- a/src/lessons/welcome/array/search/SecondMaxValueEntity.java +++ b/src/lessons/welcome/array/search/SecondMaxValueEntity.java @@ -11,7 +11,7 @@ public void run() int count = getTestCount(); for (int i = 0; i < count; i++) { Object[] param = (Object[])deserialize(getTest(i)); - setTestResult(i, serialize(max2Value(toPrimitive(toArrayOfType(param[0], Integer.class))))); + setTestResult(i, serialize(max2Value((int[]) param[0]))); } } diff --git a/src/plm/core/ValueSerializer.java b/src/plm/core/ValueSerializer.java index d8b582307..1509e150b 100644 --- a/src/plm/core/ValueSerializer.java +++ b/src/plm/core/ValueSerializer.java @@ -1,245 +1,280 @@ package plm.core; -import java.lang.reflect.Array; -import java.util.Arrays; -import java.util.Vector; +import java.util.*; +import java.util.stream.Collectors; public class ValueSerializer { - @SuppressWarnings("unchecked") - public static T[] toArrayOfType(Object original, Class newType) { + private static String getTypeRepresentation(Class clazz) { + assert !clazz.isArray(); - if(original instanceof int[]) { - int[] array = (int[]) original; - Integer[] newArray = new Integer[array.length]; - for(int i = 0; i < array.length; i++) - newArray[i] = array[i]; - return toArrayOfType(newArray, newType); - } + if (clazz == Integer.class || clazz == int.class) return "i"; + if (clazz == Double.class || clazz == double.class) return "f"; + if (clazz == Boolean.class || clazz == boolean.class) return "b"; - if(original instanceof double[]) { - double[] array = (double[]) original; - Double[] newArray = new Double[array.length]; - for(int i = 0; i < array.length; i++) - newArray[i] = array[i]; - return toArrayOfType(newArray, newType); + if (clazz == Object.class || clazz == String.class) return ""; + throw new IllegalArgumentException("Unknown serializable type: " + clazz.getSimpleName()); } - if(original instanceof boolean[]) { - boolean[] array = (boolean[]) original; - Boolean[] newArray = new Boolean[array.length]; - for(int i = 0; i < array.length; i++) - newArray[i] = array[i]; - return toArrayOfType(newArray, newType); - } + /* --- Serialization logic --- */ + public static String serialize(Object o) { + if (o == null) return "Z"; - if(newType.arrayType().isInstance(original)) return (T[]) original; - Object[] array = (Object[]) original; - - - Object o = Array.newInstance(newType, array.length); - T[] newArray = (T[]) o; - for(int i = 0; i < array.length; i++) - newArray[i] = (T) array[i]; - return newArray; - } - - public static int[] toPrimitive(Integer[] array){ - int[] newArray = new int[array.length]; - for(int i = 0; i < array.length; i++) - newArray[i] = array[i]; - return newArray; - } - - public static double[] toPrimitive(Double[] array){ - double[] newArray = new double[array.length]; - for(int i = 0; i < array.length; i++) - newArray[i] = array[i]; - return newArray; - } - - public static boolean[] toPrimitive(Boolean[] array){ - boolean[] newArray = new boolean[array.length]; - for(int i = 0; i < array.length; i++) - newArray[i] = array[i]; - return newArray; - } - - /* --- Serialization logic --- */ - public static String serialize(Object o) - { - StringBuilder sb = new StringBuilder(); - if (o == null) { - return "Z"; - } + Class clazz = o.getClass(); + if (o instanceof Collection || clazz.isArray()) { - if (o.getClass().equals(Vector.class) || o.getClass().isArray()) { - sb.append('['); - // Primitive types must be handled explicitely, as int cannot be casted to Object for a generic case. - if (o.getClass().getComponentType().equals(Integer.TYPE)) { - assert o instanceof int[]; - int[] a = (int[])o; - sb.append(a.length); - for (int i : a) - sb.append(":i" + i); - } else if (o.getClass().getComponentType().equals(Double.TYPE)) { - assert o instanceof double[]; - double[] a = (double[])o; - sb.append(a.length); - for (double i : a) - sb.append(":f" + i); - } else if (o.getClass().getComponentType().equals(Boolean.TYPE)) { - assert o instanceof boolean[]; - boolean[] a = (boolean[])o; - sb.append(a.length); - for (boolean b : a) - sb.append(b ? ":b1" : ":b0"); - - } else if (o instanceof Object[]) { - Object[] a = (Object[])o; - sb.append(a.length); - for (Object o2 : a) { - if (o2 == null) - sb.append(":Z"); - else if (o2 instanceof Integer) - sb.append(":i" + o2); - else if (o2 instanceof Double) - sb.append(":f" + o2); - else if (o2 instanceof Boolean) - sb.append(((Boolean)o2) ? ":b1" : ":b0"); - else if (o2 instanceof String) { - String escaped = ((String)o2).replace("\\", "\\\\").replace("\"", "\\\""); - sb.append(":\"" + escaped + "\""); - } else if (o2.getClass().equals(Vector.class) || o2.getClass().isArray()) - sb.append(":" + serialize(o2)); - else - throw new UnsupportedOperationException("ValueFormatter.serialize: unsupported array component type: " + o2.getClass().getName()); - } - } - sb.append(']'); - } else if (o instanceof String) { - String escaped = ((String)o).replace("\\", "\\\\").replace("\"", "\\\""); - sb.append("\"" + escaped + "\""); - } else if (o instanceof Boolean) { - Boolean b = (Boolean)o; - sb.append(b ? "b1" : "b0"); - } else if (o instanceof Integer) { - sb.append("i" + o); - } else if (o instanceof Double) { - sb.append("f" + o); - } else { - sb.append(o.toString()); - } - return sb.toString(); - } - - /* --- Deserialization logic --- */ - public static Object deserialize(String input) - { - if (input == null || input.equals("Z")) - return null; - return new Parser(input).parse(); - } - - private static class Parser { - private final String input; - private int pos = 0; - - Parser(String input) { this.input = input; } - - Object parse() - { - if (pos >= input.length()) { - throw new IllegalArgumentException("Unexpected end of input at position " + pos+" in "+input); - } - - char c = input.charAt(pos); - if (c == 'Z') - return null; - if (c == '[') - return parseArray(); - if (c == '"') - return parseString(); - return parsePrimitive(); - } + List values; + String typeRepresentation; + + if (o instanceof Collection objects) { + values = Arrays.asList(objects.toArray()); + typeRepresentation = objects.isEmpty() ? "" : getTypeRepresentation(objects.iterator().next().getClass()); + } else { + typeRepresentation = getTypeRepresentation(clazz.getComponentType()); + if (o instanceof int[] ints) { + values = Arrays.stream(ints).boxed().toList(); + } else if (o instanceof double[] doubles) { + values = Arrays.stream(doubles).boxed().toList(); + } else if (o instanceof boolean[] booleans) { + // Arrays.stream is not implemented for booleans... + List booleanValues = new ArrayList<>(); + for (boolean b : booleans) { + Boolean boo = b ? Boolean.TRUE : Boolean.FALSE; + booleanValues.add(boo); + } + values = booleanValues; + } else { + values = Arrays.stream((Object[]) o).toList(); + } + } + + return typeRepresentation + + "[" + + values.size() + + values.stream().map(ValueSerializer::serialize).map(s -> ":" + s).collect(Collectors.joining()) + + "]"; + } + + if (o instanceof String value) { + String escaped = value + .replace("\\", "\\\\") + .replace("\"", "\\\""); + return "\"" + escaped + "\""; + } + + String typeRepresentation = getTypeRepresentation(clazz); - private Object[] parseArray() - { - pos++; // Skip '[' - if (input.charAt(pos) == '0') { - pos += 2; - return new Object[0]; - } - - int colonIdx = input.indexOf(':', pos); - if (colonIdx == -1) { - throw new IllegalArgumentException("Expected ':' after array length at position " + pos+" in "+input); - } - - int len = Integer.parseInt(input.substring(pos, colonIdx)); - pos = colonIdx + 1; // Skip ':' - - Object[] arr = new Object[len]; - for (int i = 0; i < len; i++) { - arr[i] = parse(); - if (i < len - 1) { - if (input.charAt(pos) != ':') { - throw new IllegalArgumentException("Expected ':' between array elements at position " + pos+" in "+input); - } - pos++; // Skip ':' - } - } - - if (pos >= input.length() || input.charAt(pos) != ']') { - throw new IllegalArgumentException("Expected ']' at end of array at position " + pos+" in "+input); - } - pos++; // Skip ']' - return arr; + if (typeRepresentation.equals("b")) { + return "b" + (Objects.equals(o, true) ? "1" : "0"); + } + return typeRepresentation + o; } - private String parseString() - { - pos++; // Skip opening '"' - StringBuilder sb = new StringBuilder(); - while (pos < input.length()) { - char c = input.charAt(pos); - if (c == '\\' && pos + 1 < input.length() && input.charAt(pos + 1) == '"') { - sb.append('"'); - pos += 2; - } else if (c == '"') { - pos++; // Skip closing '"' - return sb.toString(); - } else { - sb.append(c); - pos++; - } - } - throw new IllegalArgumentException("Unterminated string starting at position " + (pos - sb.length() - 1)+" in "+input); + /* --- Deserialization logic --- */ + + public static Object deserialize(String text) { + Parser parser = new Parser(text); + Object value = parser.parseValue(); + if (!parser.isFinished()) { + throw new IllegalArgumentException("Unexpected trailing characters."); + } + return value; } - private Object parsePrimitive() - { - int start = pos; - while (pos < input.length() && input.charAt(pos) != ':' && input.charAt(pos) != ']') { - pos++; - } - char typeHint = input.charAt(start); - String val = input.substring(start + 1, pos); - - try { - switch (typeHint) { - case 'i': - return Integer.parseInt(val); - case 'b': - return val.equals("1"); - case 'f': - return Double.parseDouble(val); - default: // Fallback if format string is exhausted or mismatched - throw new IllegalArgumentException("Parse error: Invalid type hint '" + typeHint + "' at position " + start + " in input \"" + input + "\""+" in "+input); - } - } catch (NumberFormatException e) { - throw new IllegalArgumentException(e); - } + private static final class Parser { + + private final String text; + private int pos = 0; + + Parser(String text) { + this.text = text; + } + + private static boolean isNumberChar(char c) { + return Character.isDigit(c) || c == '-'; + } + + private static boolean isDoubleChar(char c) { + return Character.isDigit(c) + || c == '-' + || c == '.' + || c == 'e' + || c == 'E' + || c == '+'; + } + + /* ---------- Arrays ---------- */ + + boolean isFinished() { + return pos == text.length(); + } + + Object parseValue() { + char c = peek(); + + if (c == 'Z') { + pos++; + return null; + } + + if (c == '"') { + return parseString(); + } + + if (c == 'i') { + pos++; + if (peek() == '[') { + return parseIntArray(); + } + return parseInt(); + } + + if (c == 'f') { + pos++; + if (peek() == '[') { + return parseDoubleArray(); + } + return parseDouble(); + } + + if (c == 'b') { + pos++; + if (peek() == '[') { + return parseBooleanArray(); + } + return parseBoolean(); + } + + if (c == '[') { + return parseObjectArray(); + } + + throw new IllegalArgumentException("Unexpected character '" + c + "' at " + pos); + } + + private int[] parseIntArray() { + Object[] values = parseArrayContents(); + int[] result = new int[values.length]; + for (int i = 0; i < values.length; i++) { + result[i] = (Integer) values[i]; + } + return result; + } + + private double[] parseDoubleArray() { + Object[] values = parseArrayContents(); + double[] result = new double[values.length]; + for (int i = 0; i < values.length; i++) { + result[i] = (Double) values[i]; + } + return result; + } + + private boolean[] parseBooleanArray() { + Object[] values = parseArrayContents(); + boolean[] result = new boolean[values.length]; + for (int i = 0; i < values.length; i++) { + result[i] = (Boolean) values[i]; + } + return result; + } + + /* ---------- Primitive values ---------- */ + + private Object[] parseObjectArray() { + return parseArrayContents(); + } + + private Object[] parseArrayContents() { + expect('['); + + int size = parseUnsignedInt(); + + Object[] values = new Object[size]; + + for (int i = 0; i < size; i++) { + expect(':'); + values[i] = parseValue(); + } + + expect(']'); + + return values; + } + + private Integer parseInt() { + int start = pos; + while (!isFinished() && isNumberChar(peek())) { + pos++; + } + return Integer.parseInt(text.substring(start, pos)); + } + + private Double parseDouble() { + int start = pos; + while (!isFinished() && isDoubleChar(peek())) { + pos++; + } + return Double.parseDouble(text.substring(start, pos)); + } + + /* ---------- Helpers ---------- */ + + private Boolean parseBoolean() { + char c = peek(); + pos++; + return switch (c) { + case '0' -> false; + case '1' -> true; + default -> throw new IllegalArgumentException("Invalid boolean"); + }; + } + + private String parseString() { + expect('"'); + + StringBuilder sb = new StringBuilder(); + + while (true) { + if (isFinished()) { + throw new IllegalArgumentException("Unterminated string"); + } + + char c = text.charAt(pos++); + + if (c == '\\') { + if (isFinished()) { + throw new IllegalArgumentException("Invalid escape"); + } + sb.append(text.charAt(pos++)); + } else if (c == '"') { + break; + } else { + sb.append(c); + } + } + + return sb.toString(); + } + + private int parseUnsignedInt() { + int start = pos; + while (!isFinished() && Character.isDigit(peek())) { + pos++; + } + return Integer.parseInt(text.substring(start, pos)); + } + + private char peek() { + return text.charAt(pos); + } + + private void expect(char c) { + if (isFinished() || text.charAt(pos) != c) { + throw new IllegalArgumentException( + "Expected '" + c + "' at " + pos); + } + pos++; + } } - } } \ No newline at end of file diff --git a/src/plm/core/ValueSerializerTest.java b/src/plm/core/ValueSerializerTest.java index 9599200b4..ec6efe047 100644 --- a/src/plm/core/ValueSerializerTest.java +++ b/src/plm/core/ValueSerializerTest.java @@ -27,14 +27,14 @@ public class ValueSerializerTest { assertEquals("\"he\\\"llo\"", ValueSerializer.serialize("he\"llo")); } - @Test void serialize_intArray_returnsFormattedString() { assertEquals("[3:i1:i2:i3]", ValueSerializer.serialize(new int[] {1, 2, 3})); } - @Test void serialize_IntegerArray_returnsFormattedString() { assertEquals("[2:i1:i2]", ValueSerializer.serialize(new Integer[] {1, 2})); } + @Test void serialize_intArray_returnsFormattedString() { assertEquals("i[3:i1:i2:i3]", ValueSerializer.serialize(new int[] {1, 2, 3})); } + @Test void serialize_IntegerArray_returnsFormattedString() { assertEquals("i[2:i1:i2]", ValueSerializer.serialize(new Integer[] {1, 2})); } - @Test void serialize_doubleArray_returnsFormattedString() { assertEquals("[2:f1.5:f-2.2]", ValueSerializer.serialize(new double[] {1.5, -2.2})); } - @Test void serialize_DoubleArray_returnsFormattedString() { assertEquals("[2:f1.5:f-2.2]", ValueSerializer.serialize(new Double[] {1.5, -2.2})); } + @Test void serialize_doubleArray_returnsFormattedString() { assertEquals("f[2:f1.5:f-2.2]", ValueSerializer.serialize(new double[] {1.5, -2.2})); } + @Test void serialize_DoubleArray_returnsFormattedString() { assertEquals("f[2:f1.5:f-2.2]", ValueSerializer.serialize(new Double[] {1.5, -2.2})); } @Test void serialize_stringArray_returnsFormattedString() { assertEquals("[2:\"a\":\"b\"]", ValueSerializer.serialize(new String[] {"a", "b"})); } - @Test void serialize_booleanArray_returnsFormattedString() { assertEquals("[2:b1:b0]", ValueSerializer.serialize(new boolean[] {true, false})); } - @Test void serialize_BooleanArray_returnsFormattedString() { assertEquals("[2:b1:b0]", ValueSerializer.serialize(new Boolean[] {true, false})); } + @Test void serialize_booleanArray_returnsFormattedString() { assertEquals("b[2:b1:b0]", ValueSerializer.serialize(new boolean[] {true, false})); } + @Test void serialize_BooleanArray_returnsFormattedString() { assertEquals("b[2:b1:b0]", ValueSerializer.serialize(new Boolean[] {true, false})); } @Test void serialize_mixedObjectArray_returnsFormattedString() { Object[] input = {"Hi", 2}; @@ -44,7 +44,7 @@ public class ValueSerializerTest { @Test void serialize_emptyArray_returnsZeroLength() { assertEquals("[0]", ValueSerializer.serialize(new Object[] {})); - assertEquals("[0]", ValueSerializer.serialize(new int[] {})); + assertEquals("i[0]", ValueSerializer.serialize(new int[] {})); } @Test void serialize_nestedArray_serializesCorrectly()