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