Skip to content

Instantly share code, notes, and snippets.

@lehoff
Created October 5, 2016 03:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lehoff/198848f4ea0824cee5b75edae87ca2af to your computer and use it in GitHub Desktop.
Save lehoff/198848f4ea0824cee5b75edae87ca2af to your computer and use it in GitHub Desktop.
Potentially more efficient PB decoding
-module(pb_decode).
-compile(export_all).
%% existing code
d_msg_rpberrorresp(Bin, TrUserData) ->
dfp_read_field_def_rpberrorresp(Bin, 0, 0,
id(undefined, TrUserData),
id(undefined, TrUserData), TrUserData).
dfp_read_field_def_rpberrorresp(<<10, Rest/binary>>, Z1,
Z2, F1, F2, TrUserData) ->
d_field_rpberrorresp_errmsg(Rest, Z1, Z2, F1, F2,
TrUserData);
dfp_read_field_def_rpberrorresp(<<16, Rest/binary>>, Z1,
Z2, F1, F2, TrUserData) ->
d_field_rpberrorresp_errcode(Rest, Z1, Z2, F1, F2,
TrUserData);
dfp_read_field_def_rpberrorresp(<<>>, 0, 0, F1, F2,
_) ->
#rpberrorresp{errmsg = F1, errcode = F2};
dfp_read_field_def_rpberrorresp(Other, Z1, Z2, F1, F2,
TrUserData) ->
dg_read_field_def_rpberrorresp(Other, Z1, Z2, F1, F2,
TrUserData).
dg_read_field_def_rpberrorresp(<<1:1, X:7,
Rest/binary>>,
N, Acc, F1, F2, TrUserData)
when N < 32 - 7 ->
dg_read_field_def_rpberrorresp(Rest, N + 7,
X bsl N + Acc, F1, F2, TrUserData);
dg_read_field_def_rpberrorresp(<<0:1, X:7,
Rest/binary>>,
N, Acc, F1, F2, TrUserData) ->
Key = X bsl N + Acc,
case Key of
10 ->
d_field_rpberrorresp_errmsg(Rest, 0, 0, F1, F2,
TrUserData);
16 ->
d_field_rpberrorresp_errcode(Rest, 0, 0, F1, F2,
TrUserData);
_ ->
case Key band 7 of
0 ->
skip_varint_rpberrorresp(Rest, 0, 0, F1, F2,
TrUserData);
1 ->
skip_64_rpberrorresp(Rest, 0, 0, F1, F2, TrUserData);
2 ->
skip_length_delimited_rpberrorresp(Rest, 0, 0, F1, F2,
TrUserData);
5 ->
skip_32_rpberrorresp(Rest, 0, 0, F1, F2, TrUserData)
end
end;
dg_read_field_def_rpberrorresp(<<>>, 0, 0, F1, F2, _) ->
#rpberrorresp{errmsg = F1, errcode = F2}.
d_field_rpberrorresp_errmsg(<<1:1, X:7, Rest/binary>>,
N, Acc, F1, F2, TrUserData)
when N < 57 ->
d_field_rpberrorresp_errmsg(Rest, N + 7, X bsl N + Acc,
F1, F2, TrUserData);
d_field_rpberrorresp_errmsg(<<0:1, X:7, Rest/binary>>,
N, Acc, _, F2, TrUserData) ->
Len = X bsl N + Acc,
<<Bytes:Len/binary, Rest2/binary>> = Rest,
NewFValue = binary:copy(Bytes),
dfp_read_field_def_rpberrorresp(Rest2, 0, 0, NewFValue,
F2, TrUserData).
d_field_rpberrorresp_errcode(<<1:1, X:7, Rest/binary>>,
N, Acc, F1, F2, TrUserData)
when N < 57 ->
d_field_rpberrorresp_errcode(Rest, N + 7, X bsl N + Acc,
F1, F2, TrUserData);
d_field_rpberrorresp_errcode(<<0:1, X:7, Rest/binary>>,
N, Acc, F1, _, TrUserData) ->
NewFValue = X bsl N + Acc,
dfp_read_field_def_rpberrorresp(Rest, 0, 0, F1,
NewFValue, TrUserData).
skip_varint_rpberrorresp(<<1:1, _:7, Rest/binary>>, Z1,
Z2, F1, F2, TrUserData) ->
skip_varint_rpberrorresp(Rest, Z1, Z2, F1, F2,
TrUserData);
skip_varint_rpberrorresp(<<0:1, _:7, Rest/binary>>, Z1,
Z2, F1, F2, TrUserData) ->
dfp_read_field_def_rpberrorresp(Rest, Z1, Z2, F1, F2,
TrUserData).
skip_length_delimited_rpberrorresp(<<1:1, X:7,
Rest/binary>>,
N, Acc, F1, F2, TrUserData)
when N < 57 ->
skip_length_delimited_rpberrorresp(Rest, N + 7,
X bsl N + Acc, F1, F2, TrUserData);
skip_length_delimited_rpberrorresp(<<0:1, X:7,
Rest/binary>>,
N, Acc, F1, F2, TrUserData) ->
Length = X bsl N + Acc,
<<_:Length/binary, Rest2/binary>> = Rest,
dfp_read_field_def_rpberrorresp(Rest2, 0, 0, F1, F2,
TrUserData).
skip_32_rpberrorresp(<<_:32, Rest/binary>>, Z1, Z2, F1,
F2, TrUserData) ->
dfp_read_field_def_rpberrorresp(Rest, Z1, Z2, F1, F2,
TrUserData).
skip_64_rpberrorresp(<<_:64, Rest/binary>>, Z1, Z2, F1,
F2, TrUserData) ->
dfp_read_field_def_rpberrorresp(Rest, Z1, Z2, F1, F2,
TrUserData).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% ideas
%% once for all bytes decoding.
%% this should be in the library, not generated every time.
%% Note: this will fail if the length of the bytes is over 2^28 :-)
%% binary_to_term fails when the binary is over 2^32 in length...
decode_bytes(Binary) ->
{Length, Rest} = chop_encoded_integer(Binary),
<<Bytes:Length/binary, Rest2/binary>> = Rest,
{Bytes, Rest2}.
decode_uint32(Binary) ->
{Length, Rest} = chop_encoded_integer(Binary),
<<UInt32:Length, Rest2/binary>> = Rest,
{UInt32, Rest2}.
chop_encoded_integer(<<0:1, Len:7, Rest/binary>>) ->
{Len, Rest};
chop_encoded_integer(<<1:1, Len1:7, 0:1, Len2, Rest/binary>>) ->
Len = Len1 * 128 + Len2,
{Len, Rest};
chop_encoded_integer(<<1:1, Len1:7, 1:1, Len2:7, 0:1, Len3:7, Rest/binary>>) ->
Len = Len1 * 16384 + Len2 * 128 + Len3,
{Len, Rest};
chop_encoded_integer(<<1:1, Len1:7, 1:1, Len2:7, 1:1, Len3:7, 1:0, Len4:7, Rest/binary>>) ->
Len = Len1 * 2097152 + Len2 * 16384 + Len3 * 128 + Len4,
{Len, Rest}.
d_rpberrorresp(Bin, TrUserData) ->
d_rpberrorresp_read_field(Bin, #rpberrorresp{}, TrUserData).
d_rpberrorresp_read_field(Bin, RpbErrorResp, TrUserData) ->
{Key, Rest} = chop_encoded_integer(Bin),
d_rpberrorresp_read_field_key(Key, Rest, RpbErrorResp, TrUserData);
d_rpberrorresp_read_field(<<>>, RpbErrorResp, _TrUserData) ->
RpbErrorResp.
d_rpberrorresp_read_field_key(10, Rest, RpbErrorResp, TrUserData) ->
{Bytes, Rest2} = decode_bytes(Rest),
d_rpberrorresp_read_field(Rest2, RpbErrorResp#rpberrorresp{errmsg=Bytes}, TrUserData);
d_rpberrorresp_read_field_key(16, Rest, RpbErrorResp, TrUserData) ->
{UInt32, Rest2} = decode_uint32(Rest),
d_rpberrorresp_read_field(Rest2, RpbErrorResp#rpberrorresp{errcode=UInt32});
d_rpberrorresp_read_field_key(Key, Rest, RpbErrorResp, TrUserData) ->
case Key band 7 of
0 ->
skip_varint_rpberrorresp(Rest, 0, 0, F1, F2,
TrUserData);
1 ->
skip_64_rpberrorresp(Rest, 0, 0, F1, F2, TrUserData);
2 ->
skip_length_delimited_rpberrorresp(Rest, 0, 0, F1, F2,
TrUserData);
5 ->
skip_32_rpberrorresp(Rest, 0, 0, F1, F2, TrUserData)
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment