219 lines
5.3 KiB
Java
219 lines
5.3 KiB
Java
package speiger.src.coreengine.utils.io.dataTag.special;
|
|
|
|
import java.io.IOException;
|
|
import java.util.List;
|
|
import java.util.StringJoiner;
|
|
import java.util.function.Consumer;
|
|
|
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
|
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap;
|
|
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
|
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap.Entry;
|
|
import speiger.src.collections.objects.sets.ObjectSet;
|
|
import speiger.src.collections.objects.utils.ObjectSets;
|
|
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
|
|
import speiger.src.coreengine.utils.io.dataTag.DataTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.compression.DataTagLimiter;
|
|
import speiger.src.coreengine.utils.io.dataTag.compression.TagCompressor;
|
|
import speiger.src.coreengine.utils.io.dataTag.compression.TagDecompressor;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.PrimitiveTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.StringTag;
|
|
import speiger.src.coreengine.utils.io.streams.ExtendedDataInput;
|
|
import speiger.src.coreengine.utils.io.streams.ExtendedDataOutput;
|
|
|
|
public class MapTag implements IMapTag
|
|
{
|
|
Object2ObjectMap<String, DataTag> tags = new Object2ObjectLinkedOpenHashMap<String, DataTag>();
|
|
|
|
public MapTag()
|
|
{
|
|
}
|
|
|
|
public MapTag(String id, DataTag tag)
|
|
{
|
|
if(tag instanceof ListTag) putList(id, tag.cast());
|
|
else if(tag instanceof MapTag) putMap(id, tag.cast());
|
|
else putTag(id, tag);
|
|
}
|
|
|
|
@Override
|
|
public int getId()
|
|
{
|
|
return 17;
|
|
}
|
|
|
|
@Override
|
|
public String getTypeName()
|
|
{
|
|
return "Map";
|
|
}
|
|
|
|
@Override
|
|
public long countBytes(long input)
|
|
{
|
|
input += 4;
|
|
for(Entry<String, DataTag> entry : Object2ObjectMaps.fastIterable(tags))
|
|
{
|
|
input += 1;
|
|
input = entry.getValue().countBytes(input);
|
|
}
|
|
return input;
|
|
}
|
|
|
|
@Override
|
|
public void addKeys(Consumer<String> keys)
|
|
{
|
|
for(Entry<String, DataTag> entry : Object2ObjectMaps.fastIterable(tags))
|
|
{
|
|
keys.accept(entry.getKey());
|
|
entry.getValue().addKeys(keys);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void write(ExtendedDataOutput output, TagCompressor compressor) throws IOException
|
|
{
|
|
output.writeVarInt(tags.size());
|
|
for(Entry<String, DataTag> entry : Object2ObjectMaps.fastIterable(tags))
|
|
{
|
|
output.writeByte(entry.getValue().getId());
|
|
compressor.writeKey(entry.getKey());
|
|
entry.getValue().write(output, compressor);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void read(ExtendedDataInput input, TagDecompressor decompressor, int depthLimit, DataTagLimiter limiter) throws IOException
|
|
{
|
|
if(depthLimit >= 512)
|
|
{
|
|
throw new IllegalStateException("Depth Limit Exceeded");
|
|
}
|
|
int size = input.readVarInt();
|
|
limiter.countBytes(4 + size);
|
|
for(int i = 0;i < size;i++)
|
|
{
|
|
byte type = input.readByte();
|
|
String id = decompressor.readKey();
|
|
limiter.countBytes(4 + (id.length() * 2));
|
|
tags.put(id, decompressor.readSubTag(type, id, depthLimit + 1));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public MapTag copy()
|
|
{
|
|
MapTag tag = new MapTag();
|
|
for(Entry<String, DataTag> entry : Object2ObjectMaps.fastIterable(tags))
|
|
{
|
|
tag.tags.put(entry.getKey(), entry.getValue().copy());
|
|
}
|
|
return tag;
|
|
}
|
|
|
|
@Override
|
|
public void putTag(String id, DataTag tag)
|
|
{
|
|
if(tag == null) return;
|
|
tags.put(id, tag);
|
|
}
|
|
|
|
public boolean contains(String id)
|
|
{
|
|
return tags.containsKey(id);
|
|
}
|
|
|
|
public boolean contains(String id, int tagType)
|
|
{
|
|
DataTag tag = tags.get(id);
|
|
return tag != null && ((tagType == 99 && tag instanceof PrimitiveTag) || tag.getId() == tagType);
|
|
}
|
|
|
|
@Override
|
|
public DataTag get(String id)
|
|
{
|
|
return tags.get(id);
|
|
}
|
|
|
|
public DataTag remove(String id)
|
|
{
|
|
return tags.remove(id);
|
|
}
|
|
|
|
public boolean isEmpty()
|
|
{
|
|
return tags.isEmpty();
|
|
}
|
|
|
|
public int size()
|
|
{
|
|
return tags.size();
|
|
}
|
|
|
|
public ObjectSet<String> keySet()
|
|
{
|
|
return ObjectSets.unmodifiable(tags.keySet());
|
|
}
|
|
|
|
public ObjectSet<Entry<String, DataTag>> entrySet()
|
|
{
|
|
return ObjectSets.unmodifiable(tags.object2ObjectEntrySet());
|
|
}
|
|
|
|
@Override
|
|
public int hashCode()
|
|
{
|
|
return tags.hashCode();
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj)
|
|
{
|
|
return obj instanceof MapTag && ((MapTag)obj).tags.equals(tags);
|
|
}
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
StringJoiner joiner = new StringJoiner(",", "{", "}");
|
|
List<String> keys = new ObjectArrayList<>(tags.keySet());
|
|
keys.sort(null);
|
|
for(int i = 0, m = keys.size();i < m;i++)
|
|
{
|
|
joiner.add(StringTag.quoteAndEscapeBuilder(keys.get(i)).append(":").append(tags.get(keys.get(i))).toString());
|
|
}
|
|
return joiner.toString();
|
|
}
|
|
|
|
@Override
|
|
public String prettyPrint(String indent, int depth)
|
|
{
|
|
if(tags.isEmpty())
|
|
{
|
|
return "{}";
|
|
}
|
|
List<String> keys = new ObjectArrayList<>(tags.keySet());
|
|
keys.sort(null);
|
|
StringBuilder builder = new StringBuilder().append("{");
|
|
String s = DataTag.repeate(indent, depth+1);
|
|
if(!indent.isEmpty())
|
|
{
|
|
builder.append('\n');
|
|
}
|
|
for(int i = 0,m=keys.size();i<m;i++)
|
|
{
|
|
builder.append(s).append(KEY_HIGHLIGHT).append(keys.get(i)).append(RESET_HIGHLIGHT).append(": ").append(tags.get(keys.get(i)).prettyPrint(indent, depth+1));
|
|
if(i + 1 < m)
|
|
{
|
|
builder.append(",").append(indent.isEmpty() ? " " : '\n');
|
|
}
|
|
}
|
|
if(!indent.isEmpty())
|
|
{
|
|
builder.append('\n').append(DataTag.repeate(indent, depth));
|
|
}
|
|
builder.append("}");
|
|
return builder.toString();
|
|
}
|
|
}
|