package org.springblade.modules.words; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * @author yongxuan.he * @date 2020/3/17 */ public class NumHelper { public enum SerializableType { /** 大小在-128~127之间的整数,占用空间为1字节 */ TINY_INT(1), /** 大小在-32768~32767之间的整数,占用空间为2字节 */ SMALL_INT(2), /** 大小在-8388608~8388607之间的整数,占用空间为3字节 */ MEDIUM_INT(3), /** int类型 */ INT(4), ; private final int flag; private static Map typeMap; static { Map tmpMap = new HashMap<>(); for (SerializableType type : SerializableType.values()) { tmpMap.put(type.getFlag(), type); } typeMap = tmpMap; } public static SerializableType getType(int flag) { return typeMap.get(flag); } SerializableType(int flag) { this.flag = flag; } public int getFlag() { return flag; } } private interface Serializer { byte[] serialize(int a); } private static Serializer tinyIntWriter = v -> { if (v < -128 || v > 127) { throw new RuntimeException("not tinyInt: " + v); } ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(v); return out.toByteArray(); }; private static Serializer smallIntWriter = v -> { if (v < -32768 || v > 32767) { throw new RuntimeException("not smallInt: " + v); } ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write((v >>> 8) & 0xFF); out.write(v & 0xFF); return out.toByteArray(); }; private static Serializer mediumIntWriter = v -> { if (v < -8388608 || v > 8388607) { throw new RuntimeException("not mediumInt: " + v); } ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write((v >>> 16) & 0xFF); out.write((v >>> 8) & 0xFF); out.write(v & 0xFF); return out.toByteArray(); }; private static Serializer intWriter = v -> { ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write((v >>> 24) & 0xFF); out.write((v >>> 16) & 0xFF); out.write((v >>> 8) & 0xFF); out.write(v & 0xFF); return out.toByteArray(); }; private static final Map simpleWriterMap = new ConcurrentHashMap<>(); static { simpleWriterMap.put(SerializableType.TINY_INT, tinyIntWriter); simpleWriterMap.put(SerializableType.SMALL_INT, smallIntWriter); simpleWriterMap.put(SerializableType.MEDIUM_INT, mediumIntWriter); simpleWriterMap.put(SerializableType.INT, intWriter); } public static byte[] serialize(int v) { ByteArrayOutputStream out = new ByteArrayOutputStream(); Serializer serializer; int typeFlag; if(v >= -128 && v<= 127) { serializer = simpleWriterMap.get(SerializableType.TINY_INT); typeFlag = SerializableType.TINY_INT.getFlag(); } else if(v >= -32768 && v <= 32767) { serializer = simpleWriterMap.get(SerializableType.SMALL_INT); typeFlag = SerializableType.SMALL_INT.getFlag(); } else if(v >= -8388608 && v <= 8388607){ serializer = simpleWriterMap.get(SerializableType.MEDIUM_INT); typeFlag = SerializableType.MEDIUM_INT.getFlag(); } else { serializer = simpleWriterMap.get(SerializableType.INT); typeFlag = SerializableType.INT.getFlag(); } out.write(typeFlag); byte[] bytes = serializer.serialize(v); out.write(bytes, 0, bytes.length); return out.toByteArray(); } public interface Deserializer { int deserialize(InputStream in) throws IOException; } private static Deserializer tinyIntReader = in -> { int ch = in.read(); if (ch < 0) throw new RuntimeException("deserializing"); if ((0x80 & ch) == 0x80) { ch = 0xffffff00 | ch; } return ch; }; private static Deserializer smallIntReader = in -> { int ch1 = in.read(); int ch2 = in.read(); if ((ch1 | ch2) < 0) throw new RuntimeException("deserializing"); int ch = (ch1 << 8) + ch2; if ((0x8000 & ch) == 0x8000) { ch = 0xffff0000 | ch; } return ch; }; private static Deserializer mediumIntReader = in -> { int ch1 = in.read(); int ch2 = in.read(); int ch3 = in.read(); if ((ch1 | ch2 | ch3) < 0) throw new RuntimeException("deserializing"); int ch = (ch1 << 16) + (ch2 << 8) + (ch3); if ((0x800000 & ch) == 0x800000) { ch = 0xff000000 | ch; } return ch; }; private static Deserializer intReader = in -> { int ch1 = in.read(); int ch2 = in.read(); int ch3 = in.read(); int ch4 = in.read(); if ((ch1 | ch2 | ch3 | ch4) < 0) throw new RuntimeException("deserializing"); return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4); }; private static final Map simpleReaderMap = new ConcurrentHashMap<>(); static { simpleReaderMap.put(SerializableType.TINY_INT, tinyIntReader); simpleReaderMap.put(SerializableType.SMALL_INT, smallIntReader); simpleReaderMap.put(SerializableType.MEDIUM_INT, mediumIntReader); simpleReaderMap.put(SerializableType.INT, intReader); } public static int read(InputStream in) throws IOException { int flag = in.read(); SerializableType type = SerializableType.getType(flag); Deserializer deserializer = simpleReaderMap.get(type); if(deserializer == null) { throw new RuntimeException("wrong flag: " + flag); } return deserializer.deserialize(in); } }