Line data Source code
1 : #ifndef HEADER_fd_src_ballet_pb_fd_pb_wire_h 2 : #define HEADER_fd_src_ballet_pb_fd_pb_wire_h 3 : 4 : /* fd_pb_wire.h provides Protobuf wire format definitions and pure 5 : functions. */ 6 : 7 : #include "../../util/bits/fd_bits.h" 8 : #include "../../util/log/fd_log.h" 9 : 10 : /* Select a varint coding strategy */ 11 : 12 : #if defined(__BMI2__) && __LZCNT__ 13 : #include <immintrin.h> 14 : #define FD_PB_VARINT_CORE 1 /* x86 PDEP and LZCNT */ 15 : #else 16 : #define FD_PB_VARINT_CORE 0 /* portable */ 17 : #endif 18 : 19 : /* Message structure */ 20 : 21 0 : #define FD_PB_WIRE_TYPE_VARINT (0U) 22 0 : #define FD_PB_WIRE_TYPE_I64 (1U) 23 0 : #define FD_PB_WIRE_TYPE_LEN (2U) 24 0 : #define FD_PB_WIRE_TYPE_I32 (5U) 25 : 26 : static inline uint 27 : fd_pb_tag( uint wire_type, 28 0 : uint field_id ) { 29 0 : return ( field_id<<3 ) | wire_type; 30 0 : } 31 : 32 : static inline uint 33 0 : fd_pb_tag_wire_type( uint tag ) { 34 0 : return tag & 0x7U; 35 0 : } 36 : 37 : static inline uint 38 0 : fd_pb_tag_field_id( uint tag ) { 39 0 : return tag >> 3; 40 0 : } 41 : 42 : /* Max value sizes (template friendly) */ 43 : 44 : #define fd_pb_bool_max_sz (1U) 45 0 : #define fd_pb_varint32_sz_max (5U) 46 : #define fd_pb_varint64_sz_max (10U) 47 : #define fd_pb_int32_sz_max fd_pb_varint32_sz_max 48 : #define fd_pb_int64_sz_max fd_pb_varint64_sz_max 49 : #define fd_pb_uint32_sz_max fd_pb_varint32_sz_max 50 : #define fd_pb_uint64_sz_max fd_pb_varint64_sz_max 51 : #define fd_pb_sint32_sz_max fd_pb_varint32_sz_max 52 : #define fd_pb_sint64_sz_max fd_pb_varint64_sz_max 53 0 : #define fd_pb_fixed32_sz_max sizeof(uint) 54 0 : #define fd_pb_fixed64_sz_max sizeof(ulong) 55 : 56 : /* Value encoders */ 57 : 58 : static inline uchar * 59 : fd_pb_append_bool( uchar buf[ fd_pb_bool_max_sz ], 60 0 : int value ) { 61 0 : buf[0] = !!value; 62 0 : return buf+1; 63 0 : } 64 : 65 : #if FD_PB_VARINT_CORE==0 /* portable */ 66 : 67 : static inline uchar * 68 : fd_pb_append_varint32( uchar buf[ fd_pb_varint32_sz_max ], 69 : uint value ) { 70 : int msb = fd_uint_find_msb( value|1U )+1; 71 : buf[ 0 ] = (uchar)( ( msb> 7 ? 0x80 : 0 ) | ( (value>> 0) & 0x7f ) ); 72 : buf[ 1 ] = (uchar)( ( msb>14 ? 0x80 : 0 ) | ( (value>> 7) & 0x7f ) ); 73 : buf[ 2 ] = (uchar)( ( msb>21 ? 0x80 : 0 ) | ( (value>>14) & 0x7f ) ); 74 : buf[ 3 ] = (uchar)( ( msb>28 ? 0x80 : 0 ) | ( (value>>21) & 0x7f ) ); 75 : buf[ 4 ] = (uchar)( ( (value>>28) & 0x7f ) ); 76 : return buf+((msb+6)/7); 77 : } 78 : 79 : static inline uchar * 80 : fd_pb_append_varint32_sz5( uchar buf[ fd_pb_varint32_sz_max ], 81 : uint value ) { 82 : buf[ 0 ] = (uchar)( 0x80 | ( (value>> 0) & 0x7f ) ); 83 : buf[ 1 ] = (uchar)( 0x80 | ( (value>> 7) & 0x7f ) ); 84 : buf[ 2 ] = (uchar)( 0x80 | ( (value>>14) & 0x7f ) ); 85 : buf[ 3 ] = (uchar)( 0x80 | ( (value>>21) & 0x7f ) ); 86 : buf[ 4 ] = (uchar)( ( (value>>28) & 0x7f ) ); 87 : return buf+5; 88 : } 89 : 90 : static inline uchar * 91 : fd_pb_append_varint64( uchar buf[ fd_pb_varint64_sz_max ], 92 : ulong value ) { 93 : int msb = fd_ulong_find_msb( value|1U )+1; 94 : buf[ 0 ] = (uchar)( ( msb> 7 ? 0x80 : 0 ) | ( (value>> 0) & 0x7f ) ); 95 : buf[ 1 ] = (uchar)( ( msb>14 ? 0x80 : 0 ) | ( (value>> 7) & 0x7f ) ); 96 : buf[ 2 ] = (uchar)( ( msb>21 ? 0x80 : 0 ) | ( (value>>14) & 0x7f ) ); 97 : buf[ 3 ] = (uchar)( ( msb>28 ? 0x80 : 0 ) | ( (value>>21) & 0x7f ) ); 98 : buf[ 4 ] = (uchar)( ( msb>35 ? 0x80 : 0 ) | ( (value>>28) & 0x7f ) ); 99 : buf[ 5 ] = (uchar)( ( msb>42 ? 0x80 : 0 ) | ( (value>>35) & 0x7f ) ); 100 : buf[ 6 ] = (uchar)( ( msb>49 ? 0x80 : 0 ) | ( (value>>42) & 0x7f ) ); 101 : buf[ 7 ] = (uchar)( ( msb>56 ? 0x80 : 0 ) | ( (value>>49) & 0x7f ) ); 102 : buf[ 8 ] = (uchar)( ( msb>63 ? 0x80 : 0 ) | ( (value>>56) & 0x7f ) ); 103 : buf[ 9 ] = (uchar)( ( (value>>63) & 0x7f ) ); 104 : return buf+((msb+6)/7); 105 : } 106 : 107 : #elif FD_PB_VARINT_CORE==1 /* x86 PDEP and LZCNT */ 108 : 109 : static inline uchar * 110 : fd_pb_append_varint32( uchar buf[ fd_pb_varint32_sz_max ], 111 0 : uint value ) { 112 : /* Scatter bits */ 113 0 : ulong enc = _pdep_u64( value, 0x7f7f7f7f7f7f7f7fUL ); 114 : /* Count leading zeros */ 115 0 : uint lzc = (uint)_lzcnt_u64( enc|1 ); 116 : /* Generate continuation bits */ 117 0 : ulong cont = 0x80808080808080UL >> (lzc&0x38); 118 : /* Store result */ 119 0 : ulong res = enc|cont; 120 0 : FD_STORE( uint, buf, (uint)res ); 121 0 : buf[4] = (uchar)( res>>32 ); 122 0 : return buf+( 8-(lzc>>3) ); 123 0 : } 124 : 125 : static inline uchar * 126 : fd_pb_append_varint32_sz5( uchar buf[ fd_pb_varint32_sz_max ], 127 0 : uint value ) { 128 0 : FD_STORE( uint, buf, 0x80808080 | _pdep_u32( value, 0x7f7f7f7f ) ); 129 0 : buf[ 4 ] = (uchar)( (value>>28) & 0x7f ); 130 0 : return buf+5; 131 0 : } 132 : 133 : static inline uchar * 134 : fd_pb_append_varint64( uchar buf[ fd_pb_varint64_sz_max ], 135 0 : ulong value ) { 136 : /* Number of continuation bytes */ 137 0 : int len = fd_ulong_find_msb( value|1U )/7; 138 : /* Scatter bits */ 139 0 : ulong const scatter = 0x7f7f7f7f7f7f7f7fUL; 140 0 : ulong enc0 = _pdep_u64( value, scatter ); 141 0 : ulong enc1 = _pdep_u64( value>>56, scatter ); 142 : /* Generate continuation bits */ 143 0 : ulong const pattern = 0x8080808080808080UL; 144 0 : ulong cont0 = _bzhi_u64( pattern, (uint)fd_uint_min( (uint)( len <<3 ), 64 ) ); 145 0 : ulong cont1 = _bzhi_u64( pattern, (uint)( (len-8)<<3 ) ); 146 : /* Store result */ 147 0 : FD_STORE( ulong, buf, enc0|cont0 ); 148 0 : FD_STORE( ushort, buf+8, (ushort)( enc1|cont1 ) ); 149 0 : return buf+len+1; 150 0 : } 151 : 152 : #endif /* varint cores */ 153 : 154 : static inline uchar * 155 : fd_pb_append_tag( uchar buf[ fd_pb_int32_sz_max ], 156 0 : ulong tag ) { 157 0 : return fd_pb_append_varint32( buf, (uint)tag ); 158 0 : } 159 : 160 : static inline uchar * 161 : fd_pb_append_int32( uchar buf[ fd_pb_varint32_sz_max ], 162 0 : int value ) { 163 0 : return fd_pb_append_varint32( buf, (uint)value ); 164 0 : } 165 : 166 : static inline uchar * 167 : fd_pb_append_int64( uchar buf[ fd_pb_int64_sz_max ], 168 0 : long value ) { 169 0 : return fd_pb_append_varint64( buf, (ulong)value ); 170 0 : } 171 : 172 : static inline uchar * 173 : fd_pb_append_uint32( uchar buf[ fd_pb_uint32_sz_max ], 174 0 : uint value ) { 175 0 : return fd_pb_append_varint32( buf, value ); 176 0 : } 177 : 178 : static inline uchar * 179 : fd_pb_append_uint64( uchar buf[ fd_pb_uint64_sz_max ], 180 0 : ulong value ) { 181 0 : return fd_pb_append_varint64( buf, value ); 182 0 : } 183 : 184 : static inline uchar * 185 : fd_pb_append_sint32( uchar buf[ fd_pb_sint32_sz_max ], 186 0 : int value ) { 187 0 : return fd_pb_append_varint32( buf, fd_int_zz_enc( value ) ); 188 0 : } 189 : 190 : static inline uchar * 191 : fd_pb_append_sint64( uchar buf[ fd_pb_sint64_sz_max ], 192 0 : long value ) { 193 0 : return fd_pb_append_varint64( buf, fd_long_zz_enc( value ) ); 194 0 : } 195 : 196 : static inline uchar * 197 : fd_pb_append_fixed32( uchar buf[ sizeof(uint) ], 198 0 : uint value ) { 199 0 : FD_STORE( uint, buf, value ); 200 0 : return buf+sizeof(uint); 201 0 : } 202 : 203 : static inline uchar * 204 : fd_pb_append_fixed64( uchar buf[ sizeof(ulong) ], 205 0 : ulong value ) { 206 0 : FD_STORE( ulong, buf, value ); 207 0 : return buf+sizeof(ulong); 208 0 : } 209 : 210 : #endif /* HEADER_fd_src_ballet_pb_fd_pb_wire_h */