Packages

GLEB128 is a small Gleam library that provides functions for encoding and decoding LEB128 (Little Endian Base 128) integers.

Current section

Files

Jump to
gleb128 src gleb128.erl
Raw

src/gleb128.erl

-module(gleb128).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([encode_unsigned/1, encode_signed/1, decode_unsigned/1, decode_signed/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/gleb128.gleam", 7).
-spec do_encode_unsigned(integer(), gleam@bytes_tree:bytes_tree()) -> {ok,
gleam@bytes_tree:bytes_tree()} |
{error, nil}.
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_tree:append(Builder, <<Current_chunk>>)};
_ ->
Current_chunk@1 = erlang:'bor'(Current_chunk, 2#10000000),
do_encode_unsigned(
Next_chunk,
gleam@bytes_tree:append(Builder, <<Current_chunk@1>>)
)
end;
false ->
{error, nil}
end.
-file("src/gleb128.gleam", 40).
-spec do_encode_signed(integer(), gleam@bytes_tree:bytes_tree()) -> gleam@bytes_tree:bytes_tree().
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_tree:append(Builder, <<Current_chunk>>);
_ ->
Current_chunk@1 = erlang:'bor'(Current_chunk, 2#10000000),
do_encode_signed(
Next_chunk,
gleam@bytes_tree:append(Builder, <<Current_chunk@1>>)
)
end.
-file("src/gleb128.gleam", 76).
-spec do_decode_unsigned(bitstring(), integer(), integer(), integer()) -> {ok,
{integer(), integer()}} |
{error, nil}.
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, Position_accumulator + 1}};
_ ->
do_decode_unsigned(
Data,
Position_accumulator + 1,
Result_accumulator@1,
Shift_accumulator + 7
)
end;
_ ->
{error, nil}
end;
_ ->
{error, nil}
end.
-file("src/gleb128.gleam", 109).
-spec do_decode_signed(bitstring(), integer(), integer(), integer()) -> {ok,
{integer(), integer()}} |
{error, nil}.
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
)
),
Position_accumulator + 1}};
_ ->
{ok,
{Result_accumulator@1,
Position_accumulator + 1}}
end;
_ ->
do_decode_signed(
Data,
Position_accumulator + 1,
Result_accumulator@1,
Shift_accumulator@1
)
end;
_ ->
{error, nil}
end;
_ ->
{error, nil}
end.
-file("src/gleb128.gleam", 155).
-spec do_fast_decode_unsigned(integer(), integer(), integer(), integer()) -> {ok,
{integer(), integer()}} |
{error, nil}.
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, Position_accumulator + 1}};
_ ->
do_fast_decode_unsigned(
Data,
Position_accumulator + 1,
Result_accumulator@1,
Shift_accumulator + 7
)
end.
-file("src/gleb128.gleam", 178).
-spec do_fast_decode_signed(integer(), integer(), integer(), integer()) -> {ok,
{integer(), integer()}} |
{error, nil}.
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
)
),
Position_accumulator + 1}};
_ ->
{ok, {Result_accumulator@1, Position_accumulator + 1}}
end;
_ ->
do_fast_decode_signed(
Data,
Position_accumulator + 1,
Result_accumulator@1,
Shift_accumulator@1
)
end.
-file("src/gleb128.gleam", 217).
?DOC(
" Encodes an unsigned (positive) integer to a bit array containing its LEB128 representation.\n"
"\n"
" Returns an error when the given value to encode is negative.\n"
).
-spec encode_unsigned(integer()) -> {ok, bitstring()} | {error, nil}.
encode_unsigned(Value) ->
case do_encode_unsigned(Value, gleam@bytes_tree:new()) of
{ok, Result} ->
{ok, erlang:list_to_bitstring(Result)};
{error, E} ->
{error, E}
end.
-file("src/gleb128.gleam", 227).
?DOC(" Encodes an signed (positive or negative) integer to a bit array containing its LEB128 representation.\n").
-spec encode_signed(integer()) -> bitstring().
encode_signed(Value) ->
_pipe = do_encode_signed(Value, gleam@bytes_tree:new()),
erlang:list_to_bitstring(_pipe).
-file("src/gleb128.gleam", 243).
?DOC(
" Decodes a bit array containing some LEB128 integer as an unsigned (positive) integer.\n"
" \n"
" Returns a tuple containing the decoded value in its first position, followed by the count of\n"
" bytes read in its second position. Returns an error when the given data can't be decoded.\n"
" \n"
" This function is designed to optimize small inputs (whose length is less than or equal to 8 bytes)\n"
" by treating them as integers; since the input size is close to the word size of a 64-bit CPU,\n"
" the Erlang runtime will internally treat it as a \"native\" integer and not as a bignum/boxed integer\n"
" (which are stored on the heap and referenced via pointers), thus significantly reducing memory\n"
" consumption and speeding up arithmetic operations. See [erl_arith.c](https://github.com/erlang/otp/blob/55d43cd555e78b9071e514b42834ae31e2081f59/erts/emulator/beam/erl_arith.c#L146C1-L146C11).\n"
).
-spec decode_unsigned(bitstring()) -> {ok, {integer(), integer()}} |
{error, nil}.
decode_unsigned(Data) ->
case erlang:byte_size(Data) of
Size when Size =< 8 ->
case gleam_stdlib:bit_array_slice(
<<Data/bitstring, 16#00:64>>,
0,
8
) of
{ok, <<Value:64/unsigned-little>>} ->
do_fast_decode_unsigned(Value, 0, 0, 0);
_ ->
{error, nil}
end;
_ ->
do_decode_unsigned(Data, 0, 0, 0)
end.
-file("src/gleb128.gleam", 266).
?DOC(
" Decodes a bit array containing some LEB128 integer as an signed (positive or negative) integer.\n"
" \n"
" Returns a tuple containing the decoded value in its first position, followed by the count of\n"
" bytes read in its second position. Returns an error when the given data can't be decoded.\n"
" \n"
" This function is designed to optimize small inputs (whose length is less than or equal to 8 bytes)\n"
" by treating them as integers; since the input size is close to the word size of a 64-bit CPU,\n"
" the Erlang runtime will internally treat it as a \"native\" integer and not as a bignum/boxed integer\n"
" (which are stored on the heap and referenced via pointers), thus significantly reducing memory\n"
" consumption and speeding up arithmetic operations. See [erl_arith.c](https://github.com/erlang/otp/blob/55d43cd555e78b9071e514b42834ae31e2081f59/erts/emulator/beam/erl_arith.c#L146C1-L146C11).\n"
).
-spec decode_signed(bitstring()) -> {ok, {integer(), integer()}} | {error, nil}.
decode_signed(Data) ->
case erlang:byte_size(Data) of
Size when Size =< 8 ->
case gleam_stdlib:bit_array_slice(
<<Data/bitstring, 16#00:64>>,
0,
8
) of
{ok, <<Value:64/signed-little>>} ->
do_fast_decode_signed(Value, 0, 0, 0);
_ ->
{error, nil}
end;
_ ->
do_decode_signed(Data, 0, 0, 0)
end.