package squidpony;
import squidpony.squidmath.*;
import java.util.*;
/**
* Ways to produce concrete implementations of StringConvert for various data structures.
* Keeping the StringConvert producers separate from the data structures allows us to convert
* JDK types as well as to keep the parts that need ObText, and thus RegExodus, separate from
* the more general-use data structures.
* Created by Tommy Ettinger on 3/9/2017.
*/
@SuppressWarnings("unchecked")
public class Converters {
public static void appendQuoted(StringBuilder sb, String text)
{
ObText.appendQuoted(sb, text);
}
public static ObText.ContentMatcher makeMatcher(CharSequence text)
{
return ObText.makeMatcherNoComments(text);
}
public static <K> StringConvert<OrderedSet<K>> convertOrderedSet(final StringConvert<K> convert) {
CharSequence[] types = StringConvert.asArray("OrderedSet", convert.name);
StringConvert found = StringConvert.lookup(types);
if (found != null)
return found; // in this case we've already created a StringConvert for this type combination
return new StringConvert<OrderedSet<K>>(types) {
@Override
public String stringify(OrderedSet<K> item) {
StringBuilder sb = new StringBuilder(100);
K k;
for (int i = 0; i < item.size(); ) {
k = item.getAt(i);
if (item == k)
return "";
ObText.appendQuoted(sb, convert.stringify(k));
if (++i < item.size())
sb.append(' ');
}
return sb.toString();
}
@Override
public OrderedSet<K> restore(String text) {
ObText.ContentMatcher m = makeMatcher(text);
OrderedSet<K> d;
if(convert.isArray)
d = new OrderedSet<>(CrossHash.generalHasher);
else
d = new OrderedSet<>();
while (m.find()) {
if (m.hasMatch()) {
d.add(convert.restore(m.getMatch()));
}
}
return d;
}
};
}
public static <K> StringConvert<OrderedSet<K>> convertOrderedSet(final CharSequence type) {
return convertOrderedSet((StringConvert<K>) StringConvert.get(type));
}
public static <K> StringConvert<OrderedSet<K>> convertOrderedSet(final Class<K> type) {
return convertOrderedSet((StringConvert<K>) StringConvert.get(type.getSimpleName()));
}
public static <K, V> StringConvert<OrderedMap<K, V>> convertOrderedMap(final StringConvert<K> convertK, final StringConvert<V> convertV) {
CharSequence[] types = StringConvert.asArray("OrderedMap", convertK.name, convertV.name);
StringConvert found = StringConvert.lookup(types);
if (found != null)
return found; // in this case we've already created a StringConvert for this type combination
return new StringConvert<OrderedMap<K, V>>(types) {
@Override
public String stringify(OrderedMap<K, V> item) {
StringBuilder sb = new StringBuilder(100);
K k;
V v;
for (int i = 0; i < item.size(); ) {
k = item.keyAt(i);
if (k == item)
return "";
appendQuoted(sb, convertK.stringify(k));
sb.append(' ');
v = item.getAt(i);
if (v == item)
return "";
appendQuoted(sb, convertV.stringify(v));
if (++i < item.size())
sb.append(' ');
}
return sb.toString();
}
@Override
public OrderedMap<K, V> restore(String text) {
ObText.ContentMatcher m = makeMatcher(text);
OrderedMap<K, V> d;
if(convertK.isArray)
d = new OrderedMap<>(CrossHash.generalHasher);
else
d = new OrderedMap<>();
String t;
while (m.find()) {
if (m.hasMatch()) {
t = m.getMatch();
if (m.find() && m.hasMatch()) {
d.put(convertK.restore(t), convertV.restore(m.getMatch()));
}
}
}
return d;
}
};
}
public static <K, V> StringConvert<OrderedMap<K, V>> convertOrderedMap(final CharSequence typeK, final CharSequence typeV) {
return convertOrderedMap((StringConvert<K>) StringConvert.get(typeK), (StringConvert<V>) StringConvert.get(typeV));
}
public static <K, V> StringConvert<OrderedMap<K, V>> convertOrderedMap(final Class<K> typeK, final Class<V> typeV) {
return convertOrderedMap((StringConvert<K>) StringConvert.get(typeK.getSimpleName()),
(StringConvert<V>) StringConvert.get(typeV.getSimpleName()));
}
public static <K> StringConvert<HashSet<K>> convertHashSet(final StringConvert<K> convert) {
CharSequence[] types = StringConvert.asArray("HashSet", convert.name);
StringConvert found = StringConvert.lookup(types);
if (found != null)
return found; // in this case we've already created a StringConvert for this type combination
return new StringConvert<HashSet<K>>(types) {
@Override
public String stringify(HashSet<K> item) {
StringBuilder sb = new StringBuilder(100);
Iterator<K> it = item.iterator();
K k;
while (it.hasNext()){
k = it.next();
if (item == k)
return "";
ObText.appendQuoted(sb, convert.stringify(k));
if (it.hasNext())
sb.append(' ');
}
return sb.toString();
}
@Override
public HashSet<K> restore(String text) {
ObText.ContentMatcher m = makeMatcher(text);
HashSet<K> d = new HashSet<>();
while (m.find()) {
if (m.hasMatch()) {
d.add(convert.restore(m.getMatch()));
}
}
return d;
}
};
}
public static <K> StringConvert<HashSet<K>> convertHashSet(final CharSequence type) {
return convertHashSet((StringConvert<K>) StringConvert.get(type));
}
public static <K> StringConvert<HashSet<K>> convertHashSet(final Class<K> type) {
return convertHashSet((StringConvert<K>) StringConvert.get(type.getSimpleName()));
}
public static <K, V> StringConvert<HashMap<K, V>> convertHashMap(final StringConvert<K> convertK, final StringConvert<V> convertV) {
CharSequence[] types = StringConvert.asArray("HashMap", convertK.name, convertV.name);
StringConvert found = StringConvert.lookup(types);
if (found != null)
return found; // in this case we've already created a StringConvert for this type combination
return new StringConvert<HashMap<K, V>>(types) {
@Override
public String stringify(HashMap<K, V> item) {
StringBuilder sb = new StringBuilder(100);
K k;
V v;
Iterator<K> kit = item.keySet().iterator();
Iterator<V> vit = item.values().iterator();
while (kit.hasNext()) {
k = kit.next();
if (k == item)
return "";
appendQuoted(sb, convertK.stringify(k));
sb.append(' ');
v = vit.next();
if (v == item)
return "";
appendQuoted(sb, convertV.stringify(v));
if (kit.hasNext())
sb.append(' ');
}
return sb.toString();
}
@Override
public HashMap<K, V> restore(String text) {
ObText.ContentMatcher m = makeMatcher(text);
HashMap<K, V> d = new HashMap<>();
String t;
while (m.find()) {
if (m.hasMatch()) {
t = m.getMatch();
if (m.find() && m.hasMatch()) {
d.put(convertK.restore(t), convertV.restore(m.getMatch()));
}
}
}
return d;
}
};
}
public static <K, V> StringConvert<HashMap<K, V>> convertHashMap(final CharSequence typeK, final CharSequence typeV) {
return convertHashMap((StringConvert<K>) StringConvert.get(typeK), (StringConvert<V>) StringConvert.get(typeV));
}
public static <K, V> StringConvert<HashMap<K, V>> convertHashMap(final Class<K> typeK, final Class<V> typeV) {
return convertHashMap((StringConvert<K>) StringConvert.get(typeK.getSimpleName()),
(StringConvert<V>) StringConvert.get(typeV.getSimpleName()));
}
public static <K> StringConvert<Arrangement<K>> convertArrangement(final StringConvert<K> convert) {
CharSequence[] types = StringConvert.asArray("Arrangement", convert.name);
StringConvert found = StringConvert.lookup(types);
if (found != null)
return found; // in this case we've already created a StringConvert for this type combination
return new StringConvert<Arrangement<K>>(types) {
@Override
public String stringify(Arrangement<K> item) {
StringBuilder sb = new StringBuilder(100);
K k;
for (int i = 0; i < item.size(); ) {
k = item.keyAt(i);
if (item == k)
return "";
ObText.appendQuoted(sb, convert.stringify(k));
if (++i < item.size())
sb.append(' ');
}
return sb.toString();
}
@Override
public Arrangement<K> restore(String text) {
ObText.ContentMatcher m = makeMatcher(text);
Arrangement<K> d;
if(convert.isArray)
d = new Arrangement<>(CrossHash.generalHasher);
else
d = new Arrangement<>();
while (m.find()) {
if (m.hasMatch()) {
d.add(convert.restore(m.getMatch()));
}
}
return d;
}
};
}
public static <K> StringConvert<Arrangement<K>> convertArrangement(final CharSequence type) {
return convertArrangement((StringConvert<K>) StringConvert.get(type));
}
public static <K> StringConvert<Arrangement<K>> convertArrangement(final Class<K> type) {
return convertArrangement((StringConvert<K>) StringConvert.get(type.getSimpleName()));
}
public static <K> StringConvert<ArrayList<K>> convertArrayList(final StringConvert<K> convert) {
CharSequence[] types = StringConvert.asArray("ArrayList", convert.name);
StringConvert found = StringConvert.lookup(types);
if (found != null)
return found; // in this case we've already created a StringConvert for this type combination
return new StringConvert<ArrayList<K>>(types) {
@Override
public String stringify(ArrayList<K> item) {
StringBuilder sb = new StringBuilder(100);
K k;
for (int i = 0; i < item.size(); ) {
k = item.get(i);
if (item == k)
return "";
appendQuoted(sb, convert.stringify(k));
if (++i < item.size())
sb.append(' ');
}
return sb.toString();
}
@Override
public ArrayList<K> restore(String text) {
ObText.ContentMatcher m = makeMatcher(text);
ArrayList<K> d = new ArrayList<>();
while (m.find()) {
if (m.hasMatch()) {
d.add(convert.restore(m.getMatch()));
}
}
return d;
}
};
}
public static <K> StringConvert<ArrayList<K>> convertArrayList(final CharSequence type) {
return convertArrayList((StringConvert<K>) StringConvert.get(type));
}
public static <K> StringConvert<ArrayList<K>> convertArrayList(final Class<K> type) {
return convertArrayList((StringConvert<K>) StringConvert.get(type.getSimpleName()));
}
public static <K> StringConvert<List<K>> convertList(final StringConvert<K> convert) {
CharSequence[] types = StringConvert.asArray("List", convert.name);
StringConvert found = StringConvert.lookup(types);
if (found != null)
return found; // in this case we've already created a StringConvert for this type combination
return new StringConvert<List<K>>(types) {
@Override
public String stringify(List<K> item) {
StringBuilder sb = new StringBuilder(100);
K k;
for (int i = 0; i < item.size(); ) {
k = item.get(i);
if (item == k)
return "";
appendQuoted(sb, convert.stringify(k));
if (++i < item.size())
sb.append(' ');
}
return sb.toString();
}
@Override
public ArrayList<K> restore(String text) {
ObText.ContentMatcher m = makeMatcher(text);
ArrayList<K> d = new ArrayList<>();
while (m.find()) {
if (m.hasMatch()) {
d.add(convert.restore(m.getMatch()));
}
}
return d;
}
};
}
public static <K> StringConvert<List<K>> convertList(final CharSequence type) {
return convertList((StringConvert<K>) StringConvert.get(type));
}
public static <K> StringConvert<List<K>> convertList(final Class<K> type) {
return convertList((StringConvert<K>) StringConvert.get(type.getSimpleName()));
}
public static final StringConvert<Coord> convertCoord = new StringConvert<Coord>("Coord") {
@Override
public String stringify(Coord item) {
if(item == null) return "n";
return item.x + "," + item.y;
}
@Override
public Coord restore(String text) {
if(text == null || text.equals("n")) return null;
return Coord.get(StringKit.intFromDec(text), StringKit.intFromDec(text, text.indexOf(',') + 1, text.length()));
}
};
public static final StringConvert<Coord[]> convertArrayCoord = new StringConvert<Coord[]>(true,"Coord[]") {
@Override
public String stringify(Coord[] item) {
if(item == null)
return "N";
int len = item.length;
StringBuilder sb = new StringBuilder(len * 5);
for (int i = 0; i < len; ) {
if(item[i] == null)
sb.append('n');
else
sb.append(item[i].x).append(',').append(item[i].y);
if (++i < len)
sb.append(';');
}
return sb.toString();
}
@Override
public Coord[] restore(String text) {
if(text == null || text.equals("N"))
return null;
Coord[] coords = new Coord[StringKit.count(text, ';') + 1];
int start = -1, end = text.indexOf(',');
for (int i = 0; i < coords.length; i++) {
if(text.charAt(start+1) == 'n') {
coords[i] = null;
start = text.indexOf(';', end + 1);
}
else
coords[i] = Coord.get(StringKit.intFromDec(text, start + 1, end),
StringKit.intFromDec(text, end + 1, (start = text.indexOf(';', end + 1))));
end = text.indexOf(',', start + 1);
}
return coords;
}
};
public static final StringConvert<GreasedRegion> convertGreasedRegion = new StringConvert<GreasedRegion>("GreasedRegion") {
@Override
public String stringify(GreasedRegion item) {
return item.serializeToString();
}
@Override
public GreasedRegion restore(String text) {
return GreasedRegion.deserializeFromString(text);
}
};
public static final StringConvert<IntVLA> convertIntVLA = new StringConvert<IntVLA>("IntVLA") {
@Override
public String stringify(IntVLA item) {
return item.toString(",");
}
@Override
public IntVLA restore(String text) {
return IntVLA.deserializeFromString(text);
}
};
public static final StringConvert<FakeLanguageGen> convertFakeLanguageGen = new StringConvert<FakeLanguageGen>("FakeLanguageGen")
{
@Override
public String stringify(FakeLanguageGen item) {
return item.serializeToString();
}
@Override
public FakeLanguageGen restore(String text) {
return FakeLanguageGen.deserializeFromString(text);
}
};
public static final StringConvert<ObText> convertObText = new StringConvert<ObText>("ObText") {
@Override
public String stringify(ObText item) {
return item.serializeToString();
}
@Override
public ObText restore(String text) {
return ObText.deserializeFromString(text);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////// CORE JDK TYPES, PRIMITIVES, AND PRIMITIVE ARRAYS ARE THE ONLY TYPES AFTER THIS POINT
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Simple implementation to help when passing StringConverts around with data that is already a String.
*/
public static final StringConvert<String> convertString = new StringConvert<String>("String") {
@Override
public String stringify(String item) {
return item;
}
@Override
public String restore(String text) {
return text;
}
};
public static final StringConvert<Boolean> convertBoolean = new StringConvert<Boolean>("Boolean") {
@Override
public String stringify(Boolean item) {
return item == null ? "n" : item ? "1" : "0";
}
@Override
public Boolean restore(String text) {
char c;
return (text == null || text.isEmpty() || (c = text.charAt(0)) == 'n') ? null : c == '1';
}
};
public static final StringConvert<Byte> convertByte = new StringConvert<Byte>("Byte") {
@Override
public String stringify(Byte item) {
return item.toString();
}
@Override
public Byte restore(String text) {
return Byte.decode(text);
}
};
public static final StringConvert<Short> convertShort = new StringConvert<Short>("Short") {
@Override
public String stringify(Short item) {
return item.toString();
}
@Override
public Short restore(String text) {
return Short.decode(text);
}
};
public static final StringConvert<Integer> convertInt = new StringConvert<Integer>("Integer") {
@Override
public String stringify(Integer item) {
return item.toString();
}
@Override
public Integer restore(String text) {
return Integer.decode(text);
}
};
public static final StringConvert<Long> convertLong = new StringConvert<Long>("Long") {
@Override
public String stringify(Long item) {
return item.toString();
}
@Override
public Long restore(String text) {
return Long.decode(text);
}
};
public static final StringConvert<Float> convertFloat = new StringConvert<Float>("Float") {
@Override
public String stringify(Float item) {
return item.toString();
}
@Override
public Float restore(String text) {
return Float.parseFloat(text);
}
};
public static final StringConvert<Double> convertDouble = new StringConvert<Double>("Double") {
@Override
public String stringify(Double item) {
return item.toString();
}
@Override
public Double restore(String text) {
return Double.parseDouble(text);
}
};
public static final StringConvert<Character> convertChar = new StringConvert<Character>("Character") {
@Override
public String stringify(Character item) {
return item.toString();
}
@Override
public Character restore(String text) {
return text.charAt(0);
}
};
public static final StringConvert<boolean[]> convertArrayBoolean = new StringConvert<boolean[]>(true,"boolean[]") {
@Override
public String stringify(boolean[] item) {
return StringKit.joinAlt(item);
}
@Override
public boolean[] restore(String text) {
if(text == null || text.equals("N")) return null;
int amount = text.length();
if (amount <= 0) return new boolean[0];
boolean[] splat = new boolean[amount];
for (int i = 0; i < amount; i++) {
splat[amount] = text.charAt(i) == '1';
}
return splat;
}
};
public static final StringConvert<byte[]> convertArrayByte = new StringConvert<byte[]>(true,"byte[]") {
@Override
public String stringify(byte[] item) {
if(item == null) return "N";
return StringKit.join(",", item);
}
@Override
public byte[] restore(String text) {
if(text == null || text.equals("N")) return null;
int amount = StringKit.count(text, ",");
if (amount <= 0) return new byte[]{Byte.decode(text)};
byte[] splat = new byte[amount + 1];
int dl = 1, idx = -dl, idx2;
for (int i = 0; i < amount; i++) {
splat[i] = Byte.decode(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
splat[amount] = Byte.decode(StringKit.safeSubstring(text, idx + dl, text.length()));
} else {
splat[amount] = Byte.decode(StringKit.safeSubstring(text, idx + dl, idx2));
}
return splat;
}
};
public static final StringConvert<short[]> convertArrayShort = new StringConvert<short[]>(true,"short[]") {
@Override
public String stringify(short[] item) {
if(item == null) return "N";
return StringKit.join(",", item);
}
@Override
public short[] restore(String text) {
if(text == null || text.equals("N")) return null;
int amount = StringKit.count(text, ",");
if (amount <= 0) return new short[]{Short.decode(text)};
short[] splat = new short[amount + 1];
int dl = 1, idx = -dl, idx2;
for (int i = 0; i < amount; i++) {
splat[i] = Short.decode(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
splat[amount] = Short.decode(StringKit.safeSubstring(text, idx + dl, text.length()));
} else {
splat[amount] = Short.decode(StringKit.safeSubstring(text, idx + dl, idx2));
}
return splat;
}
};
public static final StringConvert<int[]> convertArrayInt = new StringConvert<int[]>(true,"int[]") {
@Override
public String stringify(int[] item) {
if(item == null) return "N";
return StringKit.join(",", item);
}
@Override
public int[] restore(String text) {
if(text == null || text.equals("N")) return null;
int amount = StringKit.count(text, ",");
if (amount <= 0) return new int[]{Integer.decode(text)};
int[] splat = new int[amount + 1];
int dl = 1, idx = -dl, idx2;
for (int i = 0; i < amount; i++) {
splat[i] = Integer.decode(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
splat[amount] = Integer.decode(StringKit.safeSubstring(text, idx + dl, text.length()));
} else {
splat[amount] = Integer.decode(StringKit.safeSubstring(text, idx + dl, idx2));
}
return splat;
}
};
public static final StringConvert<long[]> convertArrayLong = new StringConvert<long[]>(true,"long[]") {
@Override
public String stringify(long[] item) {
if(item == null) return "N";
return StringKit.join(",", item);
}
@Override
public long[] restore(String text) {
if(text == null || text.equals("N")) return null;
int amount = StringKit.count(text, ",");
if (amount <= 0) return new long[]{Long.decode(text)};
long[] splat = new long[amount + 1];
int dl = 1, idx = -dl, idx2;
for (int i = 0; i < amount; i++) {
splat[i] = Long.decode(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
splat[amount] = Long.decode(StringKit.safeSubstring(text, idx + dl, text.length()));
} else {
splat[amount] = Long.decode(StringKit.safeSubstring(text, idx + dl, idx2));
}
return splat;
}
};
public static final StringConvert<float[]> convertArrayFloat = new StringConvert<float[]>(true,"float[]") {
@Override
public String stringify(float[] item) {
if(item == null) return "N";
return StringKit.join(",", item);
}
@Override
public float[] restore(String text) {
if(text == null || text.equals("N")) return null;
int amount = StringKit.count(text, ",");
if (amount <= 0) return new float[]{Float.parseFloat(text)};
float[] splat = new float[amount + 1];
int dl = 1, idx = -dl, idx2;
for (int i = 0; i < amount; i++) {
splat[i] = Float.parseFloat(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
splat[amount] = Float.parseFloat(StringKit.safeSubstring(text, idx + dl, text.length()));
} else {
splat[amount] = Float.parseFloat(StringKit.safeSubstring(text, idx + dl, idx2));
}
return splat;
}
};
public static final StringConvert<double[]> convertArrayDouble = new StringConvert<double[]>(true,"double[]") {
@Override
public String stringify(double[] item) {
if(item == null) return "N";
return StringKit.join(",", item);
}
@Override
public double[] restore(String text) {
if(text == null || text.equals("N")) return null;
int amount = StringKit.count(text, ",");
if (amount <= 0) return new double[]{Double.parseDouble(text)};
double[] splat = new double[amount + 1];
int dl = 1, idx = -dl, idx2;
for (int i = 0; i < amount; i++) {
splat[i] = Double.parseDouble(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
splat[amount] = Double.parseDouble(StringKit.safeSubstring(text, idx + dl, text.length()));
} else {
splat[amount] = Double.parseDouble(StringKit.safeSubstring(text, idx + dl, idx2));
}
return splat;
}
};
public static final StringConvert<char[]> convertArrayChar = new StringConvert<char[]>(true,"char[]") {
@Override
public String stringify(char[] item) {
if(item == null) return "";
return String.valueOf(item);
}
@Override
public char[] restore(String text) {
return text.toCharArray();
}
};
public static final StringConvert<boolean[][]> convertArrayBoolean2D = new StringConvert<boolean[][]>(true, "boolean[][]") {
@Override
public String stringify(boolean[][] item) {
if(item == null)
return "N";
int len;
if((len = item.length) <= 0)
return "";
StringBuilder sb = new StringBuilder(len * 128);
if(item[0] == null)
sb.append('n');
else
sb.append(StringKit.joinAlt(item[0]));
for (int i = 1; i < len; i++) {
if(item[i] == null)
sb.append(";n");
else
sb.append(';').append(StringKit.joinAlt(item[i]));
}
return sb.toString();
}
@Override
public boolean[][] restore(String text) {
if(text == null) return null;
int len;
if((len = text.length()) <= 0) return new boolean[0][0];
if(text.charAt(0) == 'N') return null;
int width = StringKit.count(text, ';')+1;
boolean[][] val = new boolean[width][];
int start = 0, end = text.indexOf(';');
for (int i = 0; i < width; i++) {
if(start == end || start >= len) val[i] = new boolean[0];
else if(text.charAt(start) == 'n') val[i] = null;
else {
int amount = end - start;
val[i] = new boolean[amount];
for (int j = 0; j < amount; j++) {
val[i][j] = text.charAt(start + j) == '1';
}
}
start = end+1;
end = text.indexOf(';', start);
}
return val;
}
};
public static final StringConvert<byte[][]> convertArrayByte2D = new StringConvert<byte[][]>(true, "byte[][]") {
@Override
public String stringify(byte[][] item) {
if(item == null)
return "N";
int len;
if((len = item.length) <= 0)
return "";
StringBuilder sb = new StringBuilder(len * 128);
if(item[0] == null)
sb.append('n');
else
sb.append(StringKit.join(",", item[0]));
for (int i = 1; i < len; i++) {
if(item[i] == null)
sb.append(";n");
else
sb.append(';').append(StringKit.join(",", item[i]));
}
return sb.toString();
}
@Override
public byte[][] restore(String text) {
if(text == null) return null;
int len;
if((len = text.length()) <= 0) return new byte[0][0];
if(text.charAt(0) == 'N') return null;
int width = StringKit.count(text, ';')+1;
byte[][] val = new byte[width][];
int start = 0, end = text.indexOf(';');
for (int i = 0; i < width; i++) {
if(start == end || start >= len) val[i] = new byte[0];
else if(text.charAt(start) == 'n') val[i] = null;
else {
int amount = StringKit.count(text, ",", start, end);
if (amount <= 0){
val[i] = new byte[]{Byte.decode(text)};
continue;
}
val[i] = new byte[amount + 1];
int dl = 1, idx = start - dl, idx2;
for (int j = 0; j < amount; j++) {
val[i][j] = Byte.decode(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
val[i][amount] = Byte.decode(StringKit.safeSubstring(text, idx + dl, text.length()));
} else if(idx2 < end){
val[i][amount] = Byte.decode(StringKit.safeSubstring(text, idx + dl, idx2));
} else {
val[i][amount] = Byte.decode(StringKit.safeSubstring(text, idx + dl, end));
}
}
start = end+1;
end = text.indexOf(';', start);
}
return val;
}
};
public static final StringConvert<short[][]> convertArrayShort2D = new StringConvert<short[][]>(true, "short[][]") {
@Override
public String stringify(short[][] item) {
if(item == null)
return "N";
int len;
if((len = item.length) <= 0)
return "";
StringBuilder sb = new StringBuilder(len * 128);
if(item[0] == null)
sb.append('n');
else
sb.append(StringKit.join(",", item[0]));
for (int i = 1; i < len; i++) {
if(item[i] == null)
sb.append(";n");
else
sb.append(';').append(StringKit.join(",", item[i]));
}
return sb.toString();
}
@Override
public short[][] restore(String text) {
if(text == null) return null;
int len;
if((len = text.length()) <= 0) return new short[0][0];
if(text.charAt(0) == 'N') return null;
int width = StringKit.count(text, ';')+1;
short[][] val = new short[width][];
int start = 0, end = text.indexOf(';');
for (int i = 0; i < width; i++) {
if(start == end || start >= len) val[i] = new short[0];
else if(text.charAt(start) == 'n') val[i] = null;
else {
int amount = StringKit.count(text, ",", start, end);
if (amount <= 0){
val[i] = new short[]{Short.decode(text)};
continue;
}
val[i] = new short[amount + 1];
int dl = 1, idx = start - dl, idx2;
for (int j = 0; j < amount; j++) {
val[i][j] = Short.decode(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
val[i][amount] = Short.decode(StringKit.safeSubstring(text, idx + dl, text.length()));
} else if(idx2 < end){
val[i][amount] = Short.decode(StringKit.safeSubstring(text, idx + dl, idx2));
} else {
val[i][amount] = Short.decode(StringKit.safeSubstring(text, idx + dl, end));
}
}
start = end+1;
end = text.indexOf(';', start);
}
return val;
}
};
public static final StringConvert<int[][]> convertArrayInt2D = new StringConvert<int[][]>(true, "int[][]") {
@Override
public String stringify(int[][] item) {
if(item == null)
return "N";
int len;
if((len = item.length) <= 0)
return "";
StringBuilder sb = new StringBuilder(len * 128);
if(item[0] == null)
sb.append('n');
else
sb.append(StringKit.join(",", item[0]));
for (int i = 1; i < len; i++) {
if(item[i] == null)
sb.append(";n");
else
sb.append(';').append(StringKit.join(",", item[i]));
}
return sb.toString();
}
@Override
public int[][] restore(String text) {
if(text == null) return null;
int len;
if((len = text.length()) <= 0) return new int[0][0];
if(text.charAt(0) == 'N') return null;
int width = StringKit.count(text, ';')+1;
int[][] val = new int[width][];
int start = 0, end = text.indexOf(';');
for (int i = 0; i < width; i++) {
if(start == end || start >= len) val[i] = new int[0];
else if(text.charAt(start) == 'n') val[i] = null;
else {
int amount = StringKit.count(text, ",", start, end);
if (amount <= 0){
val[i] = new int[]{Integer.decode(text)};
continue;
}
val[i] = new int[amount + 1];
int dl = 1, idx = start - dl, idx2;
for (int j = 0; j < amount; j++) {
val[i][j] = Integer.decode(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
val[i][amount] = Integer.decode(StringKit.safeSubstring(text, idx + dl, text.length()));
} else if(idx2 < end){
val[i][amount] = Integer.decode(StringKit.safeSubstring(text, idx + dl, idx2));
} else {
val[i][amount] = Integer.decode(StringKit.safeSubstring(text, idx + dl, end));
}
}
start = end+1;
end = text.indexOf(';', start);
}
return val;
}
};
public static final StringConvert<long[][]> convertArrayLong2D = new StringConvert<long[][]>(true, "long[][]") {
@Override
public String stringify(long[][] item) {
if(item == null)
return "N";
int len;
if((len = item.length) <= 0)
return "";
StringBuilder sb = new StringBuilder(len * 128);
if(item[0] == null)
sb.append('n');
else
sb.append(StringKit.join(",", item[0]));
for (int i = 1; i < len; i++) {
if(item[i] == null)
sb.append(";n");
else
sb.append(';').append(StringKit.join(",", item[i]));
}
return sb.toString();
}
@Override
public long[][] restore(String text) {
if(text == null) return null;
int len;
if((len = text.length()) <= 0) return new long[0][0];
if(text.charAt(0) == 'N') return null;
int width = StringKit.count(text, ';')+1;
long[][] val = new long[width][];
int start = 0, end = text.indexOf(';');
for (int i = 0; i < width; i++) {
if(start == end || start >= len) val[i] = new long[0];
else if(text.charAt(start) == 'n') val[i] = null;
else {
int amount = StringKit.count(text, ",", start, end);
if (amount <= 0){
val[i] = new long[]{Long.decode(text)};
continue;
}
val[i] = new long[amount + 1];
int dl = 1, idx = start - dl, idx2;
for (int j = 0; j < amount; j++) {
val[i][j] = Long.decode(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
val[i][amount] = Long.decode(StringKit.safeSubstring(text, idx + dl, text.length()));
} else if(idx2 < end){
val[i][amount] = Long.decode(StringKit.safeSubstring(text, idx + dl, idx2));
} else {
val[i][amount] = Long.decode(StringKit.safeSubstring(text, idx + dl, end));
}
}
start = end+1;
end = text.indexOf(';', start);
}
return val;
}
};
public static final StringConvert<float[][]> convertArrayFloat2D = new StringConvert<float[][]>(true, "float[][]") {
@Override
public String stringify(float[][] item) {
if(item == null)
return "N";
int len;
if((len = item.length) <= 0)
return "";
StringBuilder sb = new StringBuilder(len * 128);
if(item[0] == null)
sb.append('n');
else
sb.append(StringKit.join(",", item[0]));
for (int i = 1; i < len; i++) {
if(item[i] == null)
sb.append(";n");
else
sb.append(';').append(StringKit.join(",", item[i]));
}
return sb.toString();
}
@Override
public float[][] restore(String text) {
if(text == null) return null;
int len;
if((len = text.length()) <= 0) return new float[0][0];
if(text.charAt(0) == 'N') return null;
int width = StringKit.count(text, ';')+1;
float[][] val = new float[width][];
int start = 0, end = text.indexOf(';');
for (int i = 0; i < width; i++) {
if(start == end || start >= len) val[i] = new float[0];
else if(text.charAt(start) == 'n') val[i] = null;
else {
int amount = StringKit.count(text, ",", start, end);
if (amount <= 0){
val[i] = new float[]{Float.parseFloat(text)};
continue;
}
val[i] = new float[amount + 1];
int dl = 1, idx = start - dl, idx2;
for (int j = 0; j < amount; j++) {
val[i][j] = Float.parseFloat(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
val[i][amount] = Float.parseFloat(StringKit.safeSubstring(text, idx + dl, text.length()));
} else if(idx2 < end){
val[i][amount] = Float.parseFloat(StringKit.safeSubstring(text, idx + dl, idx2));
} else {
val[i][amount] = Float.parseFloat(StringKit.safeSubstring(text, idx + dl, end));
}
}
start = end+1;
end = text.indexOf(';', start);
}
return val;
}
};
public static final StringConvert<double[][]> convertArrayDouble2D = new StringConvert<double[][]>(true, "double[][]") {
@Override
public String stringify(double[][] item) {
if(item == null)
return "N";
int len;
if((len = item.length) <= 0)
return "";
StringBuilder sb = new StringBuilder(len * 128);
if(item[0] == null)
sb.append('n');
else
sb.append(StringKit.join(",", item[0]));
for (int i = 1; i < len; i++) {
if(item[i] == null)
sb.append(";n");
else
sb.append(';').append(StringKit.join(",", item[i]));
}
return sb.toString();
}
@Override
public double[][] restore(String text) {
if(text == null) return null;
int len;
if((len = text.length()) <= 0) return new double[0][0];
if(text.charAt(0) == 'N') return null;
int width = StringKit.count(text, ';')+1;
double[][] val = new double[width][];
int start = 0, end = text.indexOf(';');
for (int i = 0; i < width; i++) {
if(start == end || start >= len) val[i] = new double[0];
else if(text.charAt(start) == 'n') val[i] = null;
else {
int amount = StringKit.count(text, ",", start, end);
if (amount <= 0){
val[i] = new double[]{Double.parseDouble(text)};
continue;
}
val[i] = new double[amount + 1];
int dl = 1, idx = start - dl, idx2;
for (int j = 0; j < amount; j++) {
val[i][j] = Double.parseDouble(StringKit.safeSubstring(text, idx + dl, idx = text.indexOf(',', idx + dl)));
}
if ((idx2 = text.indexOf(',', idx + dl)) < 0) {
val[i][amount] = Double.parseDouble(StringKit.safeSubstring(text, idx + dl, text.length()));
} else if(idx2 < end){
val[i][amount] = Double.parseDouble(StringKit.safeSubstring(text, idx + dl, idx2));
} else {
val[i][amount] = Double.parseDouble(StringKit.safeSubstring(text, idx + dl, end));
}
}
start = end+1;
end = text.indexOf(';', start);
}
return val;
}
};
public static final StringConvert<char[][]> convertArrayChar2D = new StringConvert<char[][]>(true, "char[][]") {
@Override
public String stringify(char[][] item) {
int len, l2, sum;
if (item == null) return "N"; // N for null
if((len = item.length) <= 0) return "R0|0|";
sum = l2 = item[0].length;
char regular = 'R'; // R for rectangular
for (int i = 1; i < len; i++) {
if(item[i] == null)
{
regular = 'J'; // J for jagged
}
else if(l2 != (l2 = item[i].length))
{
regular = 'J'; // J for jagged
sum += l2;
}
}
StringBuilder sb;
if(regular == 'R')
{
sb = new StringBuilder(len * l2 + 15);
sb.append('R').append(len).append('|').append(l2).append('|');
for (int i = 0; i < len; i++) {
sb.append(item[i]);
}
}
else
{
sb = new StringBuilder(len * 7 + sum + 8);
sb.append('J').append(len).append('|');
for (int i = 0; i < len; i++) {
if(item[i] == null)
sb.append("-|");
else
sb.append(item[i].length).append('|').append(item[i]);
}
}
return sb.toString();
}
@Override
public char[][] restore(String text) {
if(text == null || text.length() <= 1) return null;
if(text.charAt(0) == 'R')
{
int width, height, start = 1, end = text.indexOf('|');
width = StringKit.intFromDec(text, start, end);
start = end+1;
end = text.indexOf('|', start);
height = StringKit.intFromDec(text, start, end);
start = end+1;
char[][] val = new char[width][height];
for (int i = 0; i < width; i++) {
text.getChars(start, start += height, val[i], 0);
}
return val;
}
else
{
int width, current, start = 1, end = text.indexOf('|');
width = StringKit.intFromDec(text, start, end);
start = end + 1;
char[][] val = new char[width][];
for (int i = 0; i < width; i++) {
end = text.indexOf('|', start);
if (text.charAt(start) == '-') {
val[i] = null;
start = end + 1;
} else {
current = StringKit.intFromDec(text, start, end);
start = end + 1;
val[i] = new char[current];
text.getChars(start, start += current, val[i], 0);
}
}
return val;
}
}
};
}