Line data Source code
1 : #ifndef HEADER_fd_src_util_encoders_fd_bincode_h
2 : #define HEADER_fd_src_util_encoders_fd_bincode_h
3 :
4 : #include "../../util/fd_util.h"
5 : #include "../../util/valloc/fd_valloc.h"
6 :
7 : typedef void
8 : (* fd_types_walk_fn_t)( void * self,
9 : void const * arg,
10 : char const * name,
11 : int type,
12 : char const * type_name,
13 : uint level,
14 : uint varint );
15 :
16 : typedef void
17 : (* fd_types_walk_fn_t)( void * self,
18 : void const * arg,
19 : char const * name,
20 : int type,
21 : char const * type_name,
22 : uint level,
23 : uint varint );
24 :
25 : /* Context argument used for encoding */
26 : struct fd_bincode_encode_ctx {
27 : /* Current position in data buffer */
28 : void * data;
29 : /* End of buffer */
30 : void * dataend;
31 : };
32 : typedef struct fd_bincode_encode_ctx fd_bincode_encode_ctx_t;
33 :
34 : /* Context argument used for decoding */
35 : struct fd_bincode_decode_ctx {
36 : /* Current position in data buffer */
37 : void const * data;
38 : /* End of buffer */
39 : void const * dataend;
40 : };
41 : typedef struct fd_bincode_decode_ctx fd_bincode_decode_ctx_t;
42 :
43 56325 : #define FD_BINCODE_SUCCESS ( 0)
44 0 : #define FD_BINCODE_ERR_UNDERFLOW (-1001) /* Attempted to read past end of buffer */
45 6 : #define FD_BINCODE_ERR_OVERFLOW (-1002) /* Attempted to write past end of buffer */
46 0 : #define FD_BINCODE_ERR_ENCODING (-1003) /* Invalid encoding */
47 :
48 : #define FD_BINCODE_PRIMITIVE_STUBS( name, type ) \
49 : static inline int \
50 : fd_bincode_##name##_decode( type * self, \
51 255 : fd_bincode_decode_ctx_t * ctx ) { \
52 255 : uchar const * ptr = (uchar const *) ctx->data; \
53 255 : if ( FD_UNLIKELY((void const *)(ptr + sizeof(type)) > ctx->dataend ) ) \
54 255 : return FD_BINCODE_ERR_UNDERFLOW; \
55 255 : memcpy( self, ptr, sizeof(type) ); /* unaligned */ \
56 255 : ctx->data = ptr + sizeof(type); \
57 255 : return FD_BINCODE_SUCCESS; \
58 255 : } \
59 : static inline int \
60 49749 : fd_bincode_##name##_decode_footprint( fd_bincode_decode_ctx_t * ctx ) { \
61 49749 : uchar const * ptr = (uchar const *) ctx->data; \
62 49749 : if ( FD_UNLIKELY((void const *)(ptr + sizeof(type)) > ctx->dataend ) ) \
63 49749 : return FD_BINCODE_ERR_UNDERFLOW; \
64 49749 : ctx->data = ptr + sizeof(type); \
65 49749 : return FD_BINCODE_SUCCESS; \
66 49749 : } \
67 : static inline void \
68 : fd_bincode_##name##_decode_unsafe( type * self, \
69 3498 : fd_bincode_decode_ctx_t * ctx ) { \
70 3498 : uchar const * ptr = (uchar const *) ctx->data; \
71 3498 : memcpy( self, ptr, sizeof(type) ); /* unaligned */ \
72 3498 : ctx->data = ptr + sizeof(type); \
73 3498 : } \
74 : static inline int \
75 : fd_bincode_##name##_encode( type self, \
76 3069 : fd_bincode_encode_ctx_t * ctx ) { \
77 3069 : uchar * ptr = (uchar *)ctx->data; \
78 3069 : if ( FD_UNLIKELY((void *)(ptr + sizeof(type)) > ctx->dataend ) ) \
79 3069 : return FD_BINCODE_ERR_OVERFLOW; \
80 3069 : memcpy( ptr, &self, sizeof(type) ); /* unaligned */ \
81 3066 : ctx->data = ptr + sizeof(type); \
82 3066 : return FD_BINCODE_SUCCESS; \
83 3069 : }
84 :
85 : FD_BINCODE_PRIMITIVE_STUBS( uint8, uchar )
86 : FD_BINCODE_PRIMITIVE_STUBS( uint16, ushort )
87 : FD_BINCODE_PRIMITIVE_STUBS( uint32, uint )
88 : FD_BINCODE_PRIMITIVE_STUBS( uint64, ulong )
89 : FD_BINCODE_PRIMITIVE_STUBS( int64, long )
90 : #if FD_HAS_INT128
91 : FD_BINCODE_PRIMITIVE_STUBS( uint128, uint128 )
92 : #endif
93 : FD_BINCODE_PRIMITIVE_STUBS( double, double )
94 :
95 : static inline int
96 : fd_bincode_bool_decode( uchar * self,
97 21 : fd_bincode_decode_ctx_t * ctx ) {
98 :
99 21 : uchar const * ptr = (uchar const *)ctx->data;
100 21 : if( FD_UNLIKELY( ptr+1 > (uchar const *)ctx->dataend ) )
101 0 : return FD_BINCODE_ERR_UNDERFLOW;
102 :
103 21 : if( FD_UNLIKELY( *ptr & (~1U) ) )
104 0 : return FD_BINCODE_ERR_ENCODING;
105 :
106 21 : *self = *ptr;
107 21 : ctx->data = ptr + 1;
108 :
109 21 : return FD_BINCODE_SUCCESS;
110 21 : }
111 :
112 : static inline int
113 18 : fd_bincode_bool_decode_footprint( fd_bincode_decode_ctx_t * ctx ) {
114 :
115 18 : uchar const * ptr = (uchar const *)ctx->data;
116 18 : if( FD_UNLIKELY( ptr+1 > (uchar const *)ctx->dataend ) )
117 0 : return FD_BINCODE_ERR_UNDERFLOW;
118 :
119 18 : if( FD_UNLIKELY( *ptr & (~1U) ) )
120 0 : return FD_BINCODE_ERR_ENCODING;
121 :
122 18 : ctx->data = ptr + 1;
123 :
124 18 : return FD_BINCODE_SUCCESS;
125 18 : }
126 :
127 : static inline void
128 : fd_bincode_bool_decode_unsafe( uchar * self,
129 30 : fd_bincode_decode_ctx_t * ctx ) {
130 30 : fd_bincode_uint8_decode_unsafe( self, ctx );
131 30 : }
132 :
133 : static inline int
134 : fd_bincode_bool_encode( uchar self,
135 207 : fd_bincode_encode_ctx_t * ctx ) {
136 :
137 207 : uchar * ptr = (uchar *)ctx->data;
138 207 : if ( FD_UNLIKELY( (void *)(ptr + 1) > ctx->dataend ) )
139 0 : return FD_BINCODE_ERR_OVERFLOW;
140 :
141 207 : *ptr = !!self;
142 207 : ctx->data = ptr + 1;
143 :
144 207 : return FD_BINCODE_SUCCESS;
145 207 : }
146 :
147 : static inline int
148 : fd_bincode_bytes_decode( uchar * self,
149 : ulong len,
150 0 : fd_bincode_decode_ctx_t * ctx ) {
151 0 : uchar * ptr = (uchar *) ctx->data;
152 0 : if ( FD_UNLIKELY((ulong)( (uchar *) ctx->dataend - ptr) < len ) ) // Get wrap-around case right
153 0 : return FD_BINCODE_ERR_UNDERFLOW;
154 0 :
155 0 : fd_memcpy(self, ptr, len);
156 0 : ctx->data = ptr + len;
157 0 :
158 0 : return FD_BINCODE_SUCCESS;
159 0 : }
160 :
161 : static inline int
162 : fd_bincode_bytes_decode_footprint( ulong len,
163 219 : fd_bincode_decode_ctx_t * ctx ) {
164 219 : uchar * ptr = (uchar *) ctx->data;
165 219 : if ( FD_UNLIKELY((ulong)( (uchar *) ctx->dataend - ptr) < len ) ) { // Get wrap-around case right
166 0 : return FD_BINCODE_ERR_UNDERFLOW;
167 0 : }
168 :
169 219 : ctx->data = ptr + len;
170 :
171 219 : return FD_BINCODE_SUCCESS;
172 219 : }
173 :
174 : static inline void
175 : fd_bincode_bytes_decode_unsafe( uchar * self,
176 : ulong len,
177 621 : fd_bincode_decode_ctx_t * ctx ) {
178 621 : uchar * ptr = (uchar *) ctx->data;
179 621 : fd_memcpy(self, ptr, len);
180 621 : ctx->data = ptr + len;
181 621 : }
182 :
183 : static inline int
184 : fd_bincode_bytes_encode( uchar const * self,
185 : ulong len,
186 996 : fd_bincode_encode_ctx_t * ctx ) {
187 996 : fd_msan_check( self, len );
188 :
189 996 : uchar * ptr = (uchar *)ctx->data;
190 996 : if( FD_UNLIKELY( (void *)( ptr+len ) > ctx->dataend ) )
191 0 : return FD_BINCODE_ERR_OVERFLOW;
192 :
193 996 : fd_memcpy( ptr, self, len );
194 996 : ctx->data = ptr + len;
195 :
196 996 : return FD_BINCODE_SUCCESS;
197 996 : }
198 :
199 : /* Alternate versions of fd_cu16_dec to make the function signature more consistent with the
200 : other fd_bincode_decode functions. */
201 : static inline int
202 : fd_bincode_compact_u16_decode( ushort * self,
203 57 : fd_bincode_decode_ctx_t * ctx ) {
204 57 : const uchar * ptr = (const uchar*) ctx->data;
205 57 : if( FD_UNLIKELY( ptr==NULL ) ) {
206 0 : return FD_BINCODE_ERR_UNDERFLOW;
207 0 : }
208 :
209 57 : if( FD_LIKELY( (void *) (ptr + 1) <= ctx->dataend && !(0x80U & ptr[0]) ) ) {
210 51 : *self = (ushort)ptr[0];
211 51 : ctx->data = ptr + 1;
212 51 : return FD_BINCODE_SUCCESS;
213 51 : }
214 :
215 6 : if( FD_LIKELY( (void *) (ptr + 2) <= ctx->dataend && !(0x80U & ptr[1]) ) ) {
216 6 : if( FD_UNLIKELY( !ptr[1] ) ) /* Detect non-minimal encoding */
217 0 : return FD_BINCODE_ERR_ENCODING;
218 6 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)ptr[1])<<7));
219 6 : ctx->data = ptr + 2;
220 6 : return FD_BINCODE_SUCCESS;
221 6 : }
222 :
223 0 : if( FD_LIKELY( (void *) (ptr + 3) <= ctx->dataend && !(0xFCU & ptr[2]) ) ) {
224 0 : if( FD_UNLIKELY( !ptr[2] ) ) /* Detect non-minimal encoding */
225 0 : return FD_BINCODE_ERR_ENCODING;
226 0 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)(ptr[1]&0x7FUL))<<7) + (((ulong)ptr[2])<<14));
227 0 : ctx->data = ptr + 3;
228 0 : return FD_BINCODE_SUCCESS;
229 0 : }
230 :
231 0 : return FD_BINCODE_ERR_UNDERFLOW;
232 0 : }
233 :
234 : static inline void
235 : fd_bincode_compact_u16_decode_unsafe( ushort * self,
236 57 : fd_bincode_decode_ctx_t * ctx ) {
237 57 : const uchar * ptr = (const uchar*) ctx->data;
238 :
239 57 : if( !(0x80U & ptr[0]) ) {
240 51 : *self = (ushort)ptr[0];
241 51 : ctx->data = ptr + 1;
242 51 : return;
243 51 : }
244 :
245 6 : if( !(0x80U & ptr[1]) ) {
246 6 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)ptr[1])<<7));
247 6 : ctx->data = ptr + 2;
248 6 : return;
249 6 : }
250 :
251 0 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)(ptr[1]&0x7FUL))<<7) + (((ulong)ptr[2])<<14));
252 0 : ctx->data = ptr + 3;
253 0 : }
254 :
255 : static inline int
256 : fd_bincode_compact_u16_encode( ushort const * self,
257 12 : fd_bincode_encode_ctx_t * ctx ) {
258 12 : uchar * ptr = (uchar*) ctx->data;
259 12 : ulong val = *self;
260 :
261 12 : if ( val < 0x80UL ) {
262 12 : if ( FD_UNLIKELY((void *) (ptr + 1) > ctx->dataend ) )
263 0 : return FD_BINCODE_ERR_OVERFLOW;
264 12 : *ptr = (uchar)val;
265 12 : ctx->data = ptr + 1;
266 12 : return FD_BINCODE_SUCCESS;
267 12 : }
268 :
269 0 : else if ( val < 0x4000UL ) {
270 0 : if ( FD_UNLIKELY((void *) (ptr + 2) > ctx->dataend ) )
271 0 : return FD_BINCODE_ERR_OVERFLOW;
272 0 : ptr[0] = (uchar)((val&0x7FUL)|0x80UL);
273 0 : ptr[1] = (uchar)(val>>7);
274 0 : ctx->data = ptr + 2;
275 0 : return FD_BINCODE_SUCCESS;
276 0 : }
277 :
278 0 : else {
279 0 : if ( FD_UNLIKELY((void *) (ptr + 3) > ctx->dataend ) )
280 0 : return FD_BINCODE_ERR_OVERFLOW;
281 0 : ptr[0] = (uchar)((val&0x7FUL)|0x80UL);
282 0 : ptr[1] = (uchar)(((val>>7)&0x7FUL)|0x80UL);
283 0 : ptr[2] = (uchar)(val>>14);
284 0 : ctx->data = ptr + 3;
285 0 : return FD_BINCODE_SUCCESS;
286 0 : }
287 12 : }
288 :
289 : static inline ulong
290 0 : fd_bincode_compact_u16_size( ushort const * self ) {
291 0 : ulong val = *self;
292 :
293 0 : if ( val < 0x80UL ) {
294 0 : return 1;
295 0 : }
296 0 : else if ( val < 0x4000UL ) {
297 0 : return 2;
298 0 : }
299 0 : else {
300 0 : return 3;
301 0 : }
302 0 : }
303 :
304 : /* Decodes an integer encoded using the serde_varint algorithm:
305 : https://github.com/solana-labs/solana/blob/master/sdk/program/src/serde_varint.rs
306 :
307 : A variable number of bytes could have been used to encode the integer.
308 : The most significant bit of each byte indicates if more bytes have been used, so we keep consuming until
309 : we reach a byte where the most significant bit is 0.
310 : */
311 : static inline int
312 : fd_bincode_varint_decode( ulong * self,
313 0 : fd_bincode_decode_ctx_t * ctx ) {
314 0 : ulong out = 0UL;
315 0 : uint shift = 0U;
316 0 :
317 0 : while( FD_LIKELY( shift < 64U ) ) {
318 0 :
319 0 : if( FD_UNLIKELY( ctx->data >= ctx->dataend ) )
320 0 : return FD_BINCODE_ERR_UNDERFLOW;
321 0 :
322 0 : uint byte = *(uchar const *)ctx->data;
323 0 : ctx->data = (uchar const *)ctx->data + 1;
324 0 : out |= (byte & 0x7FUL) << shift;
325 0 :
326 0 : if( (byte & 0x80U) == 0U ) {
327 0 : if( (out>>shift) != byte )
328 0 : return FD_BINCODE_ERR_ENCODING;
329 0 : if( byte==0U && (shift!=0U || out!=0UL) )
330 0 : return FD_BINCODE_ERR_ENCODING;
331 0 : *self = out;
332 0 : return FD_BINCODE_SUCCESS;
333 0 : }
334 0 :
335 0 : shift += 7U;
336 0 :
337 0 : }
338 0 :
339 0 : return FD_BINCODE_ERR_ENCODING;
340 0 : }
341 :
342 : static inline int
343 3 : fd_bincode_varint_decode_footprint( fd_bincode_decode_ctx_t * ctx ) {
344 3 : ulong out = 0UL;
345 3 : uint shift = 0U;
346 :
347 18 : while( FD_LIKELY( shift < 64U ) ) {
348 :
349 18 : if( FD_UNLIKELY( ctx->data >= ctx->dataend ) )
350 0 : return FD_BINCODE_ERR_UNDERFLOW;
351 :
352 18 : uint byte = *(uchar const *)ctx->data;
353 18 : ctx->data = (uchar const *)ctx->data + 1;
354 18 : out |= (byte & 0x7FUL) << shift;
355 :
356 18 : if( (byte & 0x80U) == 0U ) {
357 3 : if( (out>>shift) != byte )
358 0 : return FD_BINCODE_ERR_ENCODING;
359 3 : if( byte==0U && (shift!=0U || out!=0UL) )
360 0 : return FD_BINCODE_ERR_ENCODING;
361 3 : return FD_BINCODE_SUCCESS;
362 3 : }
363 :
364 15 : shift += 7U;
365 :
366 15 : }
367 :
368 0 : return FD_BINCODE_ERR_ENCODING;
369 3 : }
370 :
371 : static inline void
372 : fd_bincode_varint_decode_unsafe( ulong * self,
373 3 : fd_bincode_decode_ctx_t * ctx ) {
374 3 : ulong out = 0UL;
375 3 : uint shift = 0U;
376 :
377 18 : for(;;) {
378 18 : uint byte = *(uchar const *)ctx->data;
379 18 : ctx->data = (uchar const *)ctx->data + 1;
380 18 : out |= (byte & 0x7FUL) << shift;
381 :
382 18 : if( (byte & 0x80U) == 0U ) {
383 3 : *self = out;
384 3 : return;
385 3 : }
386 :
387 15 : shift += 7U;
388 15 : }
389 3 : }
390 :
391 : static inline int
392 : fd_bincode_varint_encode( ulong val,
393 0 : fd_bincode_encode_ctx_t * ctx ) {
394 0 : uchar * ptr = (uchar *) ctx->data;
395 0 : while (1) {
396 0 : if ( FD_UNLIKELY((void *) (ptr + 1) > ctx->dataend ) )
397 0 : return FD_BINCODE_ERR_OVERFLOW;
398 0 : if ( val < 0x80UL ) {
399 0 : *(ptr++) = (uchar)val;
400 0 : ctx->data = ptr;
401 0 : return FD_BINCODE_SUCCESS;
402 0 : }
403 0 : *(ptr++) = (uchar)((val&0x7FUL)|0x80UL);
404 0 : val >>= 7;
405 0 : }
406 0 : }
407 :
408 : static inline ulong
409 0 : fd_bincode_varint_size( ulong val ) {
410 0 : ulong sz = 0;
411 0 : while (1) {
412 0 : if ( val < 0x80UL ) {
413 0 : return sz+1;
414 0 : }
415 0 : sz++;
416 0 : val >>= 7;
417 0 : }
418 0 : }
419 :
420 : enum {
421 : /* All meta tags must fit in 6 bits */
422 :
423 : /* Primitive types with an implicit encoding length */
424 : FD_ARCHIVE_META_CHAR = 0x1,
425 : FD_ARCHIVE_META_STRING = 0x2,
426 : FD_ARCHIVE_META_CHAR32 = 0x3,
427 : FD_ARCHIVE_META_DOUBLE = 0x4,
428 : FD_ARCHIVE_META_LONG = 0x5,
429 : FD_ARCHIVE_META_UINT = 0x6,
430 : FD_ARCHIVE_META_UINT128 = 0x7,
431 : FD_ARCHIVE_META_BOOL = 0x8,
432 : FD_ARCHIVE_META_UCHAR = 0x9,
433 : FD_ARCHIVE_META_UCHAR32 = 0xa,
434 : FD_ARCHIVE_META_UCHAR128 = 0xb,
435 : FD_ARCHIVE_META_UCHAR2048 = 0xc,
436 : FD_ARCHIVE_META_ULONG = 0xd,
437 : FD_ARCHIVE_META_USHORT = 0xe,
438 :
439 : /* Meta types which have an encoding length after the short tag */
440 : FD_ARCHIVE_META_STRUCT = 0x21,
441 : FD_ARCHIVE_META_VECTOR = 0x22,
442 : FD_ARCHIVE_META_DEQUE = 0x23,
443 : FD_ARCHIVE_META_MAP = 0x24,
444 : FD_ARCHIVE_META_TREAP = 0x25,
445 : FD_ARCHIVE_META_OPTION = 0x26,
446 : FD_ARCHIVE_META_ARRAY = 0x27,
447 : FD_ARCHIVE_META_STATIC_VECTOR = 0x28,
448 : };
449 :
450 : #define FD_ARCHIVE_META_SENTINAL (ushort)0 /* End of structure */
451 :
452 0 : static inline int fd_archive_encode_setup_length( fd_bincode_encode_ctx_t * ctx, void ** offset_out ) {
453 0 : uchar * ptr = (uchar *)ctx->data;
454 0 : if ( FD_UNLIKELY((void *)(ptr + sizeof(uint)) > ctx->dataend ) )
455 0 : return FD_BINCODE_ERR_OVERFLOW;
456 0 : /* Skip over length for now but make space for it */
457 0 : *offset_out = ptr;
458 0 : ctx->data = ptr + sizeof(uint);
459 0 : return FD_BINCODE_SUCCESS;
460 0 : }
461 :
462 0 : static inline int fd_archive_encode_set_length( fd_bincode_encode_ctx_t * ctx, void * offset ) {
463 0 : *(uint *)offset = (uint)((uchar *)ctx->data - ((uchar *)offset + sizeof(uint)));
464 0 : return FD_BINCODE_SUCCESS;
465 0 : }
466 :
467 0 : static inline int fd_archive_decode_setup_length( fd_bincode_decode_ctx_t * ctx, void ** offset_out ) {
468 0 : uchar * ptr = (uchar *)ctx->data;
469 0 : if ( FD_UNLIKELY((void *)(ptr + sizeof(uint)) > ctx->dataend ) )
470 0 : return FD_BINCODE_ERR_UNDERFLOW;
471 0 : /* Skip over length for now and verify it later */
472 0 : *offset_out = ptr;
473 0 : ctx->data = ptr + sizeof(uint);
474 0 : return FD_BINCODE_SUCCESS;
475 0 : }
476 :
477 0 : static inline int fd_archive_decode_check_length( fd_bincode_decode_ctx_t * ctx, void * offset ) {
478 0 : if( *(uint *)offset != (uint)((uchar *)ctx->data - ((uchar *)offset + sizeof(uint))) )
479 0 : return FD_BINCODE_ERR_ENCODING;
480 0 : return FD_BINCODE_SUCCESS;
481 0 : }
482 :
483 : /* Convenience API for deserializing with common allocators */
484 :
485 : /* fd_bincode_decode_spad decodes a bincode type. The result is
486 : allocated into a spad on success. On failure, no spad allocations
487 : are made.
488 :
489 : fd_bincode_decode1_spad optionally outputs the number of bytes read
490 : to *psz. */
491 :
492 : #define fd_bincode_decode1_spad( type, spad, buf, buf_sz, perr, psz ) \
493 6 : __extension__({ \
494 6 : fd_spad_t * const spad_ = (spad); \
495 6 : void const * const buf_ = (buf); \
496 6 : ulong const buf_sz_ = (buf_sz); \
497 6 : int * perr_ = (perr); \
498 6 : ulong * psz_ = (psz); \
499 6 : fd_bincode_decode_ctx_t ctx = {0}; \
500 6 : if( perr_ ) *perr_ = -1; \
501 6 : ctx.data = (void const *)( buf_ ); \
502 6 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
503 6 : ulong total_sz = 0UL; \
504 6 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
505 6 : fd_##type##_t * out = NULL; \
506 6 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
507 6 : ulong align = fd_##type##_align(); \
508 6 : void * mem = fd_spad_alloc( spad_, align, total_sz ); \
509 6 : if( FD_UNLIKELY( !mem ) ) { \
510 0 : FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in spad)", align-1UL, total_sz, fd_spad_mem_free( spad_ ) )); \
511 0 : } \
512 6 : out = fd_##type##_decode( mem, &ctx ); \
513 6 : if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_; \
514 6 : } \
515 6 : if( perr_ ) *perr_ = err; \
516 6 : out; \
517 6 : })
518 :
519 : #define fd_bincode_decode1_spad_global( type, spad, buf, buf_sz, perr, psz ) \
520 : __extension__({ \
521 : fd_spad_t * const spad_ = (spad); \
522 : void const * const buf_ = (buf); \
523 : ulong const buf_sz_ = (buf_sz); \
524 : int * perr_ = (perr); \
525 : ulong * psz_ = (psz); \
526 : fd_bincode_decode_ctx_t ctx = {0}; \
527 : if( perr_ ) *perr_ = -1; \
528 : ctx.data = (void const *)( buf_ ); \
529 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
530 : ulong total_sz = 0UL; \
531 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
532 : fd_##type##_global_t * out = NULL; \
533 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
534 : ulong align = fd_##type##_align(); \
535 : void * mem = fd_spad_alloc( spad_, align, total_sz ); \
536 : if( FD_UNLIKELY( !mem ) ) { \
537 : FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in spad)", align-1UL, total_sz, fd_spad_mem_free( spad_ ) )); \
538 : } \
539 : out = fd_##type##_decode_global( mem, &ctx ); \
540 : if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_; \
541 : } \
542 : if( perr_ ) *perr_ = err; \
543 : out; \
544 : })
545 :
546 : #define fd_bincode_decode_spad( type, spad, buf, buf_sz, perr ) \
547 6 : fd_bincode_decode1_spad( type, spad, buf, buf_sz, perr, NULL )
548 :
549 : #define fd_bincode_decode_spad_global( type, spad, buf, buf_sz, perr ) \
550 : fd_bincode_decode1_spad_global( type, spad, buf, buf_sz, perr, NULL )
551 :
552 : /* fd_bincode_decode_scratch decodes a bincode type. The result is
553 : allocated into the thread's scratch region on success. On failure,
554 : no allocations are made. */
555 :
556 : #define fd_bincode_decode1_scratch( type, buf, buf_sz, perr, psz ) \
557 0 : __extension__({ \
558 0 : void const * const buf_ = (buf); \
559 0 : ulong const buf_sz_ = (buf_sz); \
560 0 : int * perr_ = (perr); \
561 0 : ulong * psz_ = (psz); \
562 0 : fd_bincode_decode_ctx_t ctx = {0}; \
563 0 : if( perr_ ) *perr_ = -1; \
564 0 : ctx.data = (void const *)( buf_ ); \
565 0 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
566 0 : ulong total_sz = 0UL; \
567 0 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
568 0 : fd_##type##_t * out = NULL; \
569 0 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
570 0 : ulong align = fd_##type##_align(); \
571 0 : if( FD_UNLIKELY( !fd_scratch_alloc_is_safe( align, total_sz ) ) ) { \
572 0 : FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in scratch region)", align-1UL, total_sz, fd_scratch_free() )); \
573 0 : } \
574 0 : void * mem = fd_scratch_alloc( align, total_sz ); \
575 0 : out = fd_##type##_decode( mem, &ctx ); \
576 0 : if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_; \
577 0 : } \
578 0 : if( perr_ ) *perr_ = err; \
579 0 : out; \
580 0 : })
581 :
582 : #define fd_bincode_decode_scratch( type, buf, buf_sz, perr ) \
583 0 : fd_bincode_decode1_scratch( type, buf, buf_sz, perr, NULL )
584 :
585 : /* fd_bincode_decode_static decodes a statically-sized bincode type.
586 :
587 : Example usage:
588 :
589 : fd_epoch_schedule_t es[1]; int err;
590 : if( FD_UNLIKELY( fd_bincode_decode_static( epoch_schedule, es, buf, bufsz, &err ) ) ) {
591 : ... parse fail ...
592 : return;
593 : }
594 : ... parse success ... */
595 :
596 : #define fd_bincode_decode_static( type, out, buf, buf_sz, perr ) \
597 0 : __extension__({ \
598 0 : void const * const buf_ = (buf); \
599 0 : ulong const buf_sz_ = (buf_sz); \
600 0 : fd_##type##_t * res = NULL; \
601 0 : fd_bincode_decode_ctx_t ctx = {0}; \
602 0 : ctx.data = (void const *)( buf_ ); \
603 0 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
604 0 : ulong total_sz = 0UL; \
605 0 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
606 0 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
607 0 : res = fd_##type##_decode( (out), &ctx ); \
608 0 : } \
609 0 : res; \
610 0 : })
611 :
612 : #endif /* HEADER_fd_src_util_encoders_fd_bincode_h */
|