strangedb-server/src/main/java/it/cavallium/strangedb/server/TreePath.java

160 lines
3.7 KiB
Java

package it.cavallium.strangedb.server;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class TreePath {
public final TreePath parent;
private final byte[] node;
private final int offset;
private TreePath() {
parent = null;
node = null;
offset = 0;
}
private TreePath(TreePath parent, byte[] node) {
this.parent = parent;
this.node = node;
this.offset = 0;
}
private TreePath(TreePath parent, int offset) {
this.parent = parent;
this.node = null;
this.offset = offset;
}
public TreePath resolveArrayElement(int offset) {
return new TreePath(this, offset);
}
public TreePath resolveNode(byte[] child) {
return new TreePath(this, child);
}
public boolean isNodeProperty() {
return (isRoot() || node != null);
}
public boolean isArrayOffset() {
return !isNodeProperty();
}
public byte[] getNodeValue() {
if(node == null || isRoot())
throw new NullPointerException();
return node;
}
public int getArrayOffset() {
if(node != null || isRoot())
throw new NullPointerException();
return offset;
}
public boolean hasParent() {
return parent != null;
}
public TreePath getParent() {
if (parent == null)
throw new NullPointerException();
return parent;
}
@Override
public String toString() {
return toStringBuilder().toString();
}
/**
* Convert to string the actual TreePath
* @return The TreePath as a string
*/
private StringBuilder toStringBuilder() {
StringBuilder builder;
if (parent == null) {
builder = new StringBuilder();
} else {
builder = parent.toStringBuilder();
}
if (isRoot()) {
return builder;
}
if (node != null) {
if (parent != null && !parent.isRoot())
builder.append('.');
builder.append(nodeToString(node));
} else {
builder.append('[').append(offset).append(']');
}
return builder;
}
/**
* Convert node bytes to a StringBuilder
* @param node node letters
* @return node letters joined together
*/
public static StringBuilder nodeToString(byte[] node) {
StringBuilder string = new StringBuilder();
for (byte letter : node) {
string.append((char) letter);
}
return string;
}
public static byte[] stringToNode(String text) {
return text.getBytes(StandardCharsets.US_ASCII);
}
/**
* Convert a char sequence to a TreePath
* @param str char sequence
* @return The tree path
*/
public static TreePath get(CharSequence str) {
byte[] currentName = new byte[32];
byte currentNamePosition = 0;
TreePath currentTreePath = new TreePath();
for (int i = 0; i < str.length(); i++) {
byte character = (byte) str.charAt(i);
if (character >= '0' && character <= '9'
|| character >= 'A' && character <= 'Z'
|| character >= 'a' && character <= 'z'
|| character == '_') {
currentName[currentNamePosition] = character;
currentNamePosition++;
} else if((character == '.' || character == '[') && currentNamePosition > 0) {
currentTreePath = currentTreePath.resolveNode(Arrays.copyOf(currentName, currentNamePosition));
currentNamePosition = 0;
} else if (character == ']') {
if (currentNamePosition == 0) throw new NullPointerException();
int arrayOffset = toInt(Arrays.copyOf(currentName, currentNamePosition));
currentTreePath = currentTreePath.resolveArrayElement(arrayOffset);
currentNamePosition = 0;
}
}
if (currentNamePosition != 0) {
currentTreePath = currentTreePath.resolveNode(Arrays.copyOf(currentName, currentNamePosition));
}
return currentTreePath;
}
private static int toInt(byte[] number) {
int result = 0;
int tenpower = 1;
for (int i = number.length - 1; i >= 0; i--) {
result += (number[i] - '0') * tenpower;
tenpower *= 10;
}
return result;
}
public boolean isRoot() {
return parent == null;
}
}