1#pragma once
2
3#include <iostream>
4#include <Core/Types.h>
5#include <IO/ReadBuffer.h>
6#include <IO/WriteBuffer.h>
7
8
9namespace DB
10{
11
12
13/** Write UInt64 in variable length format (base128) NOTE Only up to 2^63 - 1 are supported. */
14void writeVarUInt(UInt64 x, std::ostream & ostr);
15void writeVarUInt(UInt64 x, WriteBuffer & ostr);
16char * writeVarUInt(UInt64 x, char * ostr);
17
18
19/** Read UInt64, written in variable length format (base128) */
20void readVarUInt(UInt64 & x, std::istream & istr);
21void readVarUInt(UInt64 & x, ReadBuffer & istr);
22const char * readVarUInt(UInt64 & x, const char * istr, size_t size);
23
24
25/** Get the length of UInt64 in VarUInt format */
26size_t getLengthOfVarUInt(UInt64 x);
27
28/** Get the Int64 length in VarInt format */
29size_t getLengthOfVarInt(Int64 x);
30
31
32/** Write Int64 in variable length format (base128) */
33template <typename OUT>
34inline void writeVarInt(Int64 x, OUT & ostr)
35{
36 writeVarUInt(static_cast<UInt64>((x << 1) ^ (x >> 63)), ostr);
37}
38
39inline char * writeVarInt(Int64 x, char * ostr)
40{
41 return writeVarUInt(static_cast<UInt64>((x << 1) ^ (x >> 63)), ostr);
42}
43
44
45/** Read Int64, written in variable length format (base128) */
46template <typename IN>
47inline void readVarInt(Int64 & x, IN & istr)
48{
49 readVarUInt(*reinterpret_cast<UInt64*>(&x), istr);
50 x = (static_cast<UInt64>(x) >> 1) ^ -(x & 1);
51}
52
53inline const char * readVarInt(Int64 & x, const char * istr, size_t size)
54{
55 const char * res = readVarUInt(*reinterpret_cast<UInt64*>(&x), istr, size);
56 x = (static_cast<UInt64>(x) >> 1) ^ -(x & 1);
57 return res;
58}
59
60
61inline void writeVarT(UInt64 x, std::ostream & ostr) { writeVarUInt(x, ostr); }
62inline void writeVarT(Int64 x, std::ostream & ostr) { writeVarInt(x, ostr); }
63inline void writeVarT(UInt64 x, WriteBuffer & ostr) { writeVarUInt(x, ostr); }
64inline void writeVarT(Int64 x, WriteBuffer & ostr) { writeVarInt(x, ostr); }
65inline char * writeVarT(UInt64 x, char * & ostr) { return writeVarUInt(x, ostr); }
66inline char * writeVarT(Int64 x, char * & ostr) { return writeVarInt(x, ostr); }
67
68inline void readVarT(UInt64 & x, std::istream & istr) { readVarUInt(x, istr); }
69inline void readVarT(Int64 & x, std::istream & istr) { readVarInt(x, istr); }
70inline void readVarT(UInt64 & x, ReadBuffer & istr) { readVarUInt(x, istr); }
71inline void readVarT(Int64 & x, ReadBuffer & istr) { readVarInt(x, istr); }
72inline const char * readVarT(UInt64 & x, const char * istr, size_t size) { return readVarUInt(x, istr, size); }
73inline const char * readVarT(Int64 & x, const char * istr, size_t size) { return readVarInt(x, istr, size); }
74
75
76/// For [U]Int32, [U]Int16, size_t.
77
78inline void readVarUInt(UInt32 & x, ReadBuffer & istr)
79{
80 UInt64 tmp;
81 readVarUInt(tmp, istr);
82 x = tmp;
83}
84
85inline void readVarInt(Int32 & x, ReadBuffer & istr)
86{
87 Int64 tmp;
88 readVarInt(tmp, istr);
89 x = tmp;
90}
91
92inline void readVarUInt(UInt16 & x, ReadBuffer & istr)
93{
94 UInt64 tmp;
95 readVarUInt(tmp, istr);
96 x = tmp;
97}
98
99inline void readVarInt(Int16 & x, ReadBuffer & istr)
100{
101 Int64 tmp;
102 readVarInt(tmp, istr);
103 x = tmp;
104}
105
106template <typename T>
107inline std::enable_if_t<!std::is_same_v<T, UInt64>, void>
108readVarUInt(T & x, ReadBuffer & istr)
109{
110 UInt64 tmp;
111 readVarUInt(tmp, istr);
112 x = tmp;
113}
114
115
116[[noreturn]] inline void throwReadAfterEOF()
117{
118 throw Exception("Attempt to read after eof", ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF);
119}
120
121template <bool fast>
122inline void readVarUIntImpl(UInt64 & x, ReadBuffer & istr)
123{
124 x = 0;
125 for (size_t i = 0; i < 9; ++i)
126 {
127 if constexpr (!fast)
128 if (istr.eof())
129 throwReadAfterEOF();
130
131 UInt64 byte = *istr.position();
132 ++istr.position();
133 x |= (byte & 0x7F) << (7 * i);
134
135 if (!(byte & 0x80))
136 return;
137 }
138}
139
140inline void readVarUInt(UInt64 & x, ReadBuffer & istr)
141{
142 if (istr.buffer().end() - istr.position() >= 9)
143 return readVarUIntImpl<true>(x, istr);
144 return readVarUIntImpl<false>(x, istr);
145}
146
147
148inline void readVarUInt(UInt64 & x, std::istream & istr)
149{
150 x = 0;
151 for (size_t i = 0; i < 9; ++i)
152 {
153 UInt64 byte = istr.get();
154 x |= (byte & 0x7F) << (7 * i);
155
156 if (!(byte & 0x80))
157 return;
158 }
159}
160
161inline const char * readVarUInt(UInt64 & x, const char * istr, size_t size)
162{
163 const char * end = istr + size;
164
165 x = 0;
166 for (size_t i = 0; i < 9; ++i)
167 {
168 if (istr == end)
169 throwReadAfterEOF();
170
171 UInt64 byte = *istr;
172 ++istr;
173 x |= (byte & 0x7F) << (7 * i);
174
175 if (!(byte & 0x80))
176 return istr;
177 }
178
179 return istr;
180}
181
182
183inline void writeVarUInt(UInt64 x, WriteBuffer & ostr)
184{
185 for (size_t i = 0; i < 9; ++i)
186 {
187 uint8_t byte = x & 0x7F;
188 if (x > 0x7F)
189 byte |= 0x80;
190
191 ostr.nextIfAtEnd();
192 *ostr.position() = byte;
193 ++ostr.position();
194
195 x >>= 7;
196 if (!x)
197 return;
198 }
199}
200
201
202inline void writeVarUInt(UInt64 x, std::ostream & ostr)
203{
204 for (size_t i = 0; i < 9; ++i)
205 {
206 uint8_t byte = x & 0x7F;
207 if (x > 0x7F)
208 byte |= 0x80;
209
210 ostr.put(byte);
211
212 x >>= 7;
213 if (!x)
214 return;
215 }
216}
217
218
219inline char * writeVarUInt(UInt64 x, char * ostr)
220{
221 for (size_t i = 0; i < 9; ++i)
222 {
223 uint8_t byte = x & 0x7F;
224 if (x > 0x7F)
225 byte |= 0x80;
226
227 *ostr = byte;
228 ++ostr;
229
230 x >>= 7;
231 if (!x)
232 return ostr;
233 }
234
235 return ostr;
236}
237
238
239inline size_t getLengthOfVarUInt(UInt64 x)
240{
241 return x < (1ULL << 7) ? 1
242 : (x < (1ULL << 14) ? 2
243 : (x < (1ULL << 21) ? 3
244 : (x < (1ULL << 28) ? 4
245 : (x < (1ULL << 35) ? 5
246 : (x < (1ULL << 42) ? 6
247 : (x < (1ULL << 49) ? 7
248 : (x < (1ULL << 56) ? 8
249 : 9)))))));
250}
251
252
253inline size_t getLengthOfVarInt(Int64 x)
254{
255 return getLengthOfVarUInt(static_cast<UInt64>((x << 1) ^ (x >> 63)));
256}
257
258}
259