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