linwe
2024-05-29 c10d6358b9f014375a13821465bc978d0c0da22e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
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<Integer, SerializableType> typeMap;
        static {
            Map<Integer, SerializableType> 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<SerializableType, Serializer> 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<SerializableType, Deserializer> 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);
    }
}