@@ -57,6 +57,9 @@ namespace Stockfish::Eval::NNUE {
57
57
// Size of cache line (in bytes)
58
58
constexpr std::size_t CacheLineSize = 64 ;
59
59
60
+ constexpr const char Leb128MagicString[] = " COMPRESSED_LEB128" ;
61
+ constexpr const std::size_t Leb128MagicStringSize = sizeof (Leb128MagicString) - 1 ;
62
+
60
63
// SIMD width (in bytes)
61
64
#if defined(USE_AVX2)
62
65
constexpr std::size_t SimdWidth = 32 ;
@@ -159,6 +162,80 @@ namespace Stockfish::Eval::NNUE {
159
162
write_little_endian<IntType>(stream, values[i]);
160
163
}
161
164
165
+ template <typename IntType>
166
+ inline void read_leb_128 (std::istream& stream, IntType* out, std::size_t count) {
167
+ static_assert (std::is_signed_v<IntType>, " Not implemented for unsigned types" );
168
+ char leb128MagicString[Leb128MagicStringSize];
169
+ stream.read (leb128MagicString, Leb128MagicStringSize);
170
+ assert (strncmp (Leb128MagicString, leb128MagicString, Leb128MagicStringSize) == 0 );
171
+ const std::uint32_t BUF_SIZE = 4096 ;
172
+ std::uint8_t buf[BUF_SIZE];
173
+ auto bytes_left = read_little_endian<std::uint32_t >(stream);
174
+ std::uint32_t buf_pos = BUF_SIZE;
175
+ for (std::size_t i = 0 ; i < count; ++i) {
176
+ IntType result = 0 ;
177
+ size_t shift = 0 ;
178
+ do {
179
+ if (buf_pos == BUF_SIZE) {
180
+ stream.read (reinterpret_cast <char *>(buf), std::min (bytes_left, BUF_SIZE));
181
+ buf_pos = 0 ;
182
+ }
183
+ std::uint8_t byte = buf[buf_pos++];
184
+ --bytes_left;
185
+ result |= (byte & 0x7f ) << shift;
186
+ shift += 7 ;
187
+ if ((byte & 0x80 ) == 0 ) {
188
+ out[i] = sizeof (IntType) * 8 <= shift || (byte & 0x40 ) == 0 ? result : result | ~((1 << shift) - 1 );
189
+ break ;
190
+ }
191
+ } while (shift < sizeof (IntType) * 8 );
192
+ }
193
+ assert (bytes_left == 0 );
194
+ }
195
+
196
+ template <typename IntType>
197
+ inline void write_leb_128 (std::ostream& stream, const IntType* values, std::size_t count) {
198
+ static_assert (std::is_signed_v<IntType>, " Not implemented for unsigned types" );
199
+ stream.write (Leb128MagicString, Leb128MagicStringSize);
200
+ std::uint32_t byte_count = 0 ;
201
+ for (std::size_t i = 0 ; i < count; ++i) {
202
+ IntType value = values[i];
203
+ std::uint8_t byte;
204
+ do {
205
+ byte = value & 0x7f ;
206
+ value >>= 7 ;
207
+ ++byte_count;
208
+ } while ((byte & 0x40 ) == 0 ? value != 0 : value != -1 );
209
+ }
210
+ write_little_endian (stream, byte_count);
211
+ const std::uint32_t BUF_SIZE = 4096 ;
212
+ std::uint8_t buf[BUF_SIZE];
213
+ std::uint32_t buf_pos = 0 ;
214
+ auto flush = [&]() {
215
+ if (buf_pos > 0 ) {
216
+ stream.write (reinterpret_cast <char *>(buf), buf_pos);
217
+ buf_pos = 0 ;
218
+ }
219
+ };
220
+ auto write = [&](std::uint8_t byte) {
221
+ buf[buf_pos++] = byte;
222
+ if (buf_pos == BUF_SIZE) flush ();
223
+ };
224
+ for (std::size_t i = 0 ; i < count; ++i) {
225
+ IntType value = values[i];
226
+ while (true ) {
227
+ std::uint8_t byte = value & 0x7f ;
228
+ value >>= 7 ;
229
+ if ((byte & 0x40 ) == 0 ? value == 0 : value == -1 ) {
230
+ write (byte);
231
+ break ;
232
+ }
233
+ write (byte | 0x80 );
234
+ }
235
+ }
236
+ flush ();
237
+ }
238
+
162
239
} // namespace Stockfish::Eval::NNUE
163
240
164
241
#endif // #ifndef NNUE_COMMON_H_INCLUDED
0 commit comments