mirror of
https://github.com/ProjectSWGCore/pswgcommon.git
synced 2026-01-15 23:04:19 -05:00
Created a pair class to assist in upcoming features
This commit is contained in:
192
src/com/projectswg/common/data/Pair.java
Normal file
192
src/com/projectswg/common/data/Pair.java
Normal file
@@ -0,0 +1,192 @@
|
||||
package com.projectswg.common.data;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.projectswg.common.debug.Assert;
|
||||
import com.projectswg.common.debug.Log;
|
||||
import com.projectswg.common.encoding.CachedEncode;
|
||||
import com.projectswg.common.encoding.Encodable;
|
||||
import com.projectswg.common.encoding.Encoder;
|
||||
import com.projectswg.common.encoding.StringType;
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.common.network.NetBufferStream;
|
||||
import com.projectswg.common.persistable.Persistable;
|
||||
|
||||
public class Pair<T, S> implements Encodable, Persistable {
|
||||
|
||||
private final StringType leftType;
|
||||
private final StringType rightType;
|
||||
private final Class<T> leftClass;
|
||||
private final Class<S> rightClass;
|
||||
private final CachedEncode cache;
|
||||
|
||||
private T left;
|
||||
private S right;
|
||||
|
||||
private Pair(T left, S right, Class<T> leftClass, Class<S> rightClass, StringType leftType, StringType rightType) {
|
||||
// Final checks - has to be either one or the other. These ensure other assumptions in the class will succeed
|
||||
Assert.test((leftType == null && !(left instanceof String) && !leftClass.equals(String.class)) ^ (leftType != null && (left instanceof String) && leftClass.equals(String.class)));
|
||||
Assert.test((rightType == null && !(right instanceof String) && !rightClass.equals(String.class)) ^ (rightType != null && (right instanceof String) && rightClass.equals(String.class)));
|
||||
this.leftClass = leftClass;
|
||||
this.rightClass = rightClass;
|
||||
this.leftType = leftType;
|
||||
this.rightType = rightType;
|
||||
this.cache = new CachedEncode(this::encodeImpl);
|
||||
setLeft(left);
|
||||
setRight(right);
|
||||
}
|
||||
|
||||
public T getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public S getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
public void setLeft(T val1) {
|
||||
this.left = val1;
|
||||
cache.clearCached();
|
||||
}
|
||||
|
||||
public void setRight(S val2) {
|
||||
this.right = val2;
|
||||
cache.clearCached();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(NetBuffer data) {
|
||||
setLeft(smartDecode(data, leftClass, leftType));
|
||||
setRight(smartDecode(data, rightClass, rightType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encode() {
|
||||
Objects.requireNonNull(left, "left is null in encode()");
|
||||
Objects.requireNonNull(right, "right is null in encode()");
|
||||
return cache.encode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return cache.encode().length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(NetBufferStream stream) {
|
||||
smartSave(stream, left, leftType);
|
||||
smartSave(stream, right, rightType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(NetBufferStream stream) {
|
||||
smartRead(stream, left, leftClass, leftType);
|
||||
smartRead(stream, right, rightClass, rightType);
|
||||
}
|
||||
|
||||
private byte [] encodeImpl() {
|
||||
if (left == null || right == null)
|
||||
return new byte[0];
|
||||
|
||||
byte [] left = smartEncode(this.left, leftType);
|
||||
byte [] right = smartEncode(this.right, rightType);
|
||||
byte [] combined = new byte[left.length + right.length];
|
||||
System.arraycopy(left, 0, combined, 0, left.length);
|
||||
System.arraycopy(right, 0, combined, left.length, right.length);
|
||||
return combined;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // should succeed based on checks in constructor
|
||||
private static <U> U smartDecode(NetBuffer data, Class<U> klass, StringType strType) {
|
||||
if (strType != null)
|
||||
return (U) data.getString(strType);
|
||||
return (U) data.getGeneric(klass);
|
||||
}
|
||||
|
||||
private static byte [] smartEncode(Object obj, StringType strType) {
|
||||
if (strType != null)
|
||||
return Encoder.encode(obj, strType);
|
||||
return Encoder.encode(obj);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // should succeed based on checks in constructor
|
||||
private static <U> U smartRead(NetBufferStream data, U obj, Class<U> klass, StringType strType) {
|
||||
if (strType != null)
|
||||
return (U) data.getString(strType);
|
||||
|
||||
// Try making our own persistable
|
||||
if (obj == null && Persistable.class.isAssignableFrom(klass)) {
|
||||
try {
|
||||
obj = klass.newInstance();
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
}
|
||||
}
|
||||
|
||||
// If we succeeded, read it - if not, try grabbing some generic
|
||||
if (obj instanceof Persistable) {
|
||||
((Persistable) obj).read(data);
|
||||
} else {
|
||||
obj = (U) data.getGeneric(klass);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static void smartSave(NetBufferStream data, Object obj, StringType strType) {
|
||||
if (strType != null) {
|
||||
data.addString((String) obj, strType);
|
||||
} else if (obj instanceof Persistable) {
|
||||
((Persistable) obj).save(data);
|
||||
} else {
|
||||
data.write(Encoder.encode(obj));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // it's pretty obvious T.getClass() should be Class<T>
|
||||
public static <T, S> Pair<T, S> createPair(T left, S right) {
|
||||
Objects.requireNonNull(left, "Left cannot be null in this method! Instead call createPair(left, right, leftClass, rightClass)");
|
||||
Objects.requireNonNull(right, "Right cannot be null in this method! Instead call createPair(left, right, leftClass, rightClass)");
|
||||
return createPair(left, right, (Class<T>) left.getClass(), (Class<S>) right.getClass());
|
||||
}
|
||||
|
||||
public static <T, S> Pair<T, S> createPair(T left, S right, Class<T> leftClass, Class<S> rightClass) {
|
||||
Assert.test(!(left instanceof String));
|
||||
Assert.test(!(right instanceof String));
|
||||
return new Pair<>(left, right, leftClass, rightClass, null, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // it's pretty obvious T.getClass() should be Class<T>
|
||||
public static <T> Pair<String, T> createPair(String left, T right, StringType type) {
|
||||
Objects.requireNonNull(right, "Right cannot be null in this method! Instead call createPair(left, right, type, rightClass)");
|
||||
return createPair(left, right, type, (Class<T>) right.getClass());
|
||||
}
|
||||
|
||||
public static <T> Pair<String, T> createPair(String left, T right, StringType type, Class<T> rightClass) {
|
||||
Assert.test(!(right instanceof String));
|
||||
return new Pair<>(left, right, String.class, rightClass, type, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // it's pretty obvious T.getClass() should be Class<T>
|
||||
public static <T> Pair<T, String> createPair(T left, String right, StringType type) {
|
||||
Objects.requireNonNull(left, "Left cannot be null in this method! Instead call createPair(left, right, leftClass, type)");
|
||||
return createPair(left, right, (Class<T>) left.getClass(), type);
|
||||
}
|
||||
|
||||
public static <T> Pair<T, String> createPair(T left, String right, Class<T> leftClass, StringType type) {
|
||||
Assert.test(!(left instanceof String));
|
||||
return new Pair<>(left, right, leftClass, String.class, null, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a pair with two strings
|
||||
* @param left the left string, can be null
|
||||
* @param right the right string, can be null
|
||||
* @param leftType the type of the left string: ASCII/UNICODE
|
||||
* @param rightType the type of the right string: ASCII/UNICODE
|
||||
* @return the corresponding pair
|
||||
*/
|
||||
public static Pair<String, String> createPair(String left, String right, StringType leftType, StringType rightType) {
|
||||
return new Pair<>(left, right, String.class, String.class, leftType, rightType);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user