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 tags = new Object2ObjectLinkedOpenHashMap(); 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 entry : Object2ObjectMaps.fastIterable(tags)) { input += 1; input = entry.getValue().countBytes(input); } return input; } @Override public void addKeys(Consumer keys) { for(Entry 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 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 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 keySet() { return ObjectSets.unmodifiable(tags.keySet()); } public ObjectSet> 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 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 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