Current section
Files
Jump to
Current section
Files
src/gleb128.erl
-module(gleb128).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([get_cpu_endianness/0, decode_native_unsigned_integer/2, decode_native_signed_integer/2, encode_unsigned/1, encode_signed/1, decode_unsigned/1, decode_signed/1, fast_decode_unsigned/1, fast_decode_signed/1]).
-export_type([endianness/0]).
-type endianness() :: big | little.
-spec get_cpu_endianness() -> {ok, endianness()} | {error, binary()}.
get_cpu_endianness() ->
case <<16#01:32/native>> of
<<16#01, 16#00, 16#00, 16#00>> ->
{ok, little};
<<16#00, 16#00, 16#00, 16#01>> ->
{ok, big};
_ ->
{error,
<<"Can't determine CPU's endianness. Maybe the CPU uses a mixed-endian format?"/utf8>>}
end.
-spec decode_native_unsigned_integer(bitstring(), endianness()) -> integer().
decode_native_unsigned_integer(Data, Endianness) ->
binary:decode_unsigned(Data, Endianness).
-spec decode_native_signed_integer(bitstring(), endianness()) -> integer().
decode_native_signed_integer(Data, Endianness) ->
Size_in_bits = erlang:byte_size(Data) * 8,
case {Endianness, Data} of
{little, <<X:Size_in_bits/signed-little>>} ->
X;
{big, <<X@1:Size_in_bits/signed-big>>} ->
X@1;
{_, _} ->
0
end.
-spec do_encode_unsigned(integer(), gleam@bytes_builder:bytes_builder()) -> {ok,
gleam@bytes_builder:bytes_builder()} |
{error, binary()}.
do_encode_unsigned(Value, Builder) ->
case Value >= 0 of
true ->
Current_chunk = erlang:'band'(Value, 2#01111111),
Next_chunk = erlang:'bsr'(Value, 7),
case Next_chunk of
0 ->
{ok, gleam@bytes_builder:append(Builder, <<Current_chunk>>)};
_ ->
Current_chunk@1 = erlang:'bor'(Current_chunk, 2#10000000),
do_encode_unsigned(
Next_chunk,
gleam@bytes_builder:append(Builder, <<Current_chunk@1>>)
)
end;
false ->
{error,
<<"Can't encode a negative value with an unsigned function"/utf8>>}
end.
-spec do_encode_signed(integer(), gleam@bytes_builder:bytes_builder()) -> gleam@bytes_builder:bytes_builder().
do_encode_signed(Value, Builder) ->
Current_chunk = erlang:'band'(Value, 2#01111111),
Next_chunk = erlang:'bsr'(Value, 7),
Sign = erlang:'band'(Value, 2#01000000),
Sign@1 = erlang:'bsr'(Sign, 6),
case ((Next_chunk =:= 0) andalso (Sign@1 =:= 0)) orelse ((Next_chunk =:= erlang:'bnot'(
0
))
andalso (Sign@1 =:= 1)) of
true ->
gleam@bytes_builder:append(Builder, <<Current_chunk>>);
_ ->
Current_chunk@1 = erlang:'bor'(Current_chunk, 2#10000000),
do_encode_signed(
Next_chunk,
gleam@bytes_builder:append(Builder, <<Current_chunk@1>>)
)
end.
-spec do_decode_unsigned(bitstring(), integer(), integer(), integer()) -> {ok,
integer()} |
{error, binary()}.
do_decode_unsigned(
Data,
Position_accumulator,
Result_accumulator,
Shift_accumulator
) ->
case gleam_stdlib:bit_array_slice(Data, Position_accumulator, 1) of
{ok, Slice} ->
case Slice of
<<Byte/integer>> ->
Current_chunk = erlang:'band'(Byte, 2#01111111),
Current_chunk@1 = erlang:'bsl'(
Current_chunk,
Shift_accumulator
),
Result_accumulator@1 = erlang:'bor'(
Result_accumulator,
Current_chunk@1
),
Next_chunk = erlang:'bsr'(Byte, 7),
case Next_chunk of
0 ->
{ok, Result_accumulator@1};
_ ->
do_decode_unsigned(
Data,
Position_accumulator + 1,
Result_accumulator@1,
Shift_accumulator + 7
)
end;
_ ->
{error,
<<"Can't decode the bit array slice into a byte"/utf8>>}
end;
_ ->
{error, <<"Can't get the bit array slice"/utf8>>}
end.
-spec do_decode_signed(bitstring(), integer(), integer(), integer()) -> {ok,
integer()} |
{error, binary()}.
do_decode_signed(
Data,
Position_accumulator,
Result_accumulator,
Shift_accumulator
) ->
case gleam_stdlib:bit_array_slice(Data, Position_accumulator, 1) of
{ok, Slice} ->
case Slice of
<<Byte/integer>> ->
Current_chunk = erlang:'band'(Byte, 2#01111111),
Current_chunk@1 = erlang:'bsl'(
Current_chunk,
Shift_accumulator
),
Result_accumulator@1 = erlang:'bor'(
Result_accumulator,
Current_chunk@1
),
Shift_accumulator@1 = Shift_accumulator + 7,
Next_chunk = erlang:'bsr'(Byte, 7),
case Next_chunk of
0 ->
Sign = erlang:'band'(Byte, 2#01000000),
Sign@1 = erlang:'bsr'(Sign, 6),
case Sign@1 of
1 ->
{ok,
erlang:'bor'(
Result_accumulator@1,
erlang:'bsl'(
erlang:'bnot'(0),
Shift_accumulator@1
)
)};
_ ->
{ok, Result_accumulator@1}
end;
_ ->
do_decode_signed(
Data,
Position_accumulator + 1,
Result_accumulator@1,
Shift_accumulator@1
)
end;
_ ->
{error,
<<"Can't decode the bit array slice into a byte"/utf8>>}
end;
_ ->
{error, <<"Can't get the bit array slice"/utf8>>}
end.
-spec do_fast_decode_unsigned(integer(), integer(), integer(), integer()) -> {ok,
integer()} |
{error, binary()}.
do_fast_decode_unsigned(
Data,
Position_accumulator,
Result_accumulator,
Shift_accumulator
) ->
Byte = erlang:'bsr'(Data, 8 * Position_accumulator),
Byte@1 = erlang:'band'(Byte, 16#ff),
Current_chunk = erlang:'band'(Byte@1, 2#01111111),
Current_chunk@1 = erlang:'bsl'(Current_chunk, Shift_accumulator),
Result_accumulator@1 = erlang:'bor'(Result_accumulator, Current_chunk@1),
Next_chunk = erlang:'bsr'(Byte@1, 7),
case Next_chunk of
0 ->
{ok, Result_accumulator@1};
_ ->
do_fast_decode_unsigned(
Data,
Position_accumulator + 1,
Result_accumulator@1,
Shift_accumulator + 7
)
end.
-spec do_fast_decode_signed(integer(), integer(), integer(), integer()) -> {ok,
integer()} |
{error, binary()}.
do_fast_decode_signed(
Data,
Position_accumulator,
Result_accumulator,
Shift_accumulator
) ->
Byte = erlang:'bsr'(Data, 8 * Position_accumulator),
Byte@1 = erlang:'band'(Byte, 16#ff),
Current_chunk = erlang:'band'(Byte@1, 2#01111111),
Current_chunk@1 = erlang:'bsl'(Current_chunk, Shift_accumulator),
Result_accumulator@1 = erlang:'bor'(Result_accumulator, Current_chunk@1),
Shift_accumulator@1 = Shift_accumulator + 7,
Next_chunk = erlang:'bsr'(Byte@1, 7),
case Next_chunk of
0 ->
Sign = erlang:'band'(Byte@1, 2#01000000),
Sign@1 = erlang:'bsr'(Sign, 6),
case Sign@1 of
1 ->
{ok,
erlang:'bor'(
Result_accumulator@1,
erlang:'bsl'(erlang:'bnot'(0), Shift_accumulator@1)
)};
_ ->
{ok, Result_accumulator@1}
end;
_ ->
do_fast_decode_signed(
Data,
Position_accumulator + 1,
Result_accumulator@1,
Shift_accumulator@1
)
end.
-spec encode_unsigned(integer()) -> {ok, bitstring()} | {error, binary()}.
encode_unsigned(Value) ->
case do_encode_unsigned(Value, gleam@bytes_builder:new()) of
{ok, Result} ->
{ok, erlang:list_to_bitstring(Result)};
{error, E} ->
{error, E}
end.
-spec encode_signed(integer()) -> bitstring().
encode_signed(Value) ->
_pipe = do_encode_signed(Value, gleam@bytes_builder:new()),
erlang:list_to_bitstring(_pipe).
-spec decode_unsigned(bitstring()) -> {ok, integer()} | {error, binary()}.
decode_unsigned(Data) ->
do_decode_unsigned(Data, 0, 0, 0).
-spec decode_signed(bitstring()) -> {ok, integer()} | {error, binary()}.
decode_signed(Data) ->
do_decode_signed(Data, 0, 0, 0).
-spec fast_decode_unsigned(bitstring()) -> {ok, integer()} | {error, binary()}.
fast_decode_unsigned(Data) ->
case erlang:byte_size(Data) of
S when S =< 8 ->
case get_cpu_endianness() of
{ok, Endianness} ->
do_fast_decode_unsigned(
binary:decode_unsigned(Data, Endianness),
0,
0,
0
);
{error, Reason} ->
{error, Reason}
end;
_ ->
do_decode_unsigned(Data, 0, 0, 0)
end.
-spec fast_decode_signed(bitstring()) -> {ok, integer()} | {error, binary()}.
fast_decode_signed(Data) ->
case erlang:byte_size(Data) of
S when S =< 8 ->
case get_cpu_endianness() of
{ok, Endianness} ->
do_fast_decode_signed(
decode_native_signed_integer(Data, Endianness),
0,
0,
0
);
{error, Reason} ->
{error, Reason}
end;
_ ->
do_decode_signed(Data, 0, 0, 0)
end.