diff --git a/.travis.yml b/.travis.yml index c625470d0..b2d01f3fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: erlang otp_release: - - 20.0 - - 20.1 + - 21.0 + - 21.0.4 script: - make diff --git a/src/emqx_base62.erl b/src/emqx_base62.erl index 929089f1b..690115ec2 100644 --- a/src/emqx_base62.erl +++ b/src/emqx_base62.erl @@ -14,43 +14,100 @@ -module(emqx_base62). --export([encode/1, decode/1]). +-export([encode/1, + encode/2, + decode/1, + decode/2]). -%% @doc Encode an integer to base62 string --spec(encode(non_neg_integer()) -> binary()). -encode(I) when is_integer(I) andalso I > 0 -> - list_to_binary(encode(I, [])). +%% @doc Encode any data to base62 binary +-spec encode(string() + | integer() + | binary()) -> float(). +encode(I) when is_integer(I) -> + encode(integer_to_binary(I)); +encode(S) when is_list(S)-> + encode(list_to_binary(S)); +encode(B) when is_binary(B) -> + encode(B, <<>>). -encode(I, Acc) when I < 62 -> - [char(I) | Acc]; -encode(I, Acc) -> - encode(I div 62, [char(I rem 62) | Acc]). +%% encode(D, string) -> +%% binary_to_list(encode(D)). -char(I) when I < 10 -> - $0 + I; - -char(I) when I < 36 -> - $A + I - 10; - -char(I) when I < 62 -> - $a + I - 36. - -%% @doc Decode base62 string to an integer --spec(decode(string() | binary()) -> integer()). +%% @doc Decode base62 binary to origin data binary +decode(L) when is_list(L) -> + decode(list_to_binary(L)); decode(B) when is_binary(B) -> - decode(binary_to_list(B)); -decode(S) when is_list(S) -> - decode(S, 0). + decode(B, <<>>). -decode([], I) -> - I; -decode([C|S], I) -> - decode(S, I * 62 + byte(C)). -byte(C) when $0 =< C andalso C =< $9 -> - C - $0; -byte(C) when $A =< C andalso C =< $Z -> - C - $A + 10; -byte(C) when $a =< C andalso C =< $z -> - C - $a + 36. + +%%==================================================================== +%% Internal functions +%%==================================================================== + +encode(D, string) -> + binary_to_list(encode(D)); +encode(<>, Acc) -> + CharList = [encode_char(Index1), encode_char(Index2), encode_char(Index3), encode_char(Index4)], + NewAcc = <>, + encode(Rest, NewAcc); +encode(<>, Acc) -> + CharList = [encode_char(Index1), encode_char(Index2), encode_char(Index3)], + NewAcc = <>, + encode(<<>>, NewAcc); +encode(<>, Acc) -> + CharList = [encode_char(Index1), encode_char(Index2)], + NewAcc = <>, + encode(<<>>, NewAcc); +encode(<<>>, Acc) -> + Acc. + +decode(D, integer) -> + binary_to_integer(decode(D)); +decode(D, string) -> + binary_to_list(decode(D)); +decode(<>, Acc) + when bit_size(Rest) >= 8-> + case Head == $9 of + true -> + <> = Rest, + DecodeChar = decode_char(9, Head1), + <<_:2, RestBit:6>> = <>, + NewAcc = <>, + decode(Rest1, NewAcc); + false -> + DecodeChar = decode_char(Head), + <<_:2, RestBit:6>> = <>, + NewAcc = <>, + decode(Rest, NewAcc) + end; +decode(<>, Acc) -> + DecodeChar = decode_char(Head), + LeftBitSize = bit_size(Acc) rem 8, + RightBitSize = 8 - LeftBitSize, + <<_:LeftBitSize, RestBit:RightBitSize>> = <>, + NewAcc = <>, + decode(Rest, NewAcc); +decode(<<>>, Acc) -> + Acc. + + +encode_char(I) when I < 26 -> + $A + I; +encode_char(I) when I < 52 -> + $a + I - 26; +encode_char(I) when I < 61 -> + $0 + I - 52; +encode_char(I) -> + [$9, $A + I - 61]. + +decode_char(I) when I >= $a andalso I =< $z -> + I + 26 - $a; +decode_char(I) when I >= $0 andalso I =< $8-> + I + 52 - $0; +decode_char(I) when I >= $A andalso I =< $Z-> + I - $A. + +decode_char(9, I) -> + I + 61 - $A. diff --git a/src/emqx_guid.erl b/src/emqx_guid.erl index 43855c734..fa9139ebd 100644 --- a/src/emqx_guid.erl +++ b/src/emqx_guid.erl @@ -129,5 +129,6 @@ to_base62(<>) -> emqx_base62:encode(I). from_base62(S) -> - I = emqx_base62:decode(S), <>. + I = emqx_base62:decode(S, integer), + <>. diff --git a/test/emqx_base62_SUITE.erl b/test/emqx_base62_SUITE.erl index e0cb0e26a..820c7ec32 100644 --- a/test/emqx_base62_SUITE.erl +++ b/test/emqx_base62_SUITE.erl @@ -26,11 +26,14 @@ all() -> [t_base62_encode]. t_base62_encode(_) -> - 10 = ?BASE62:decode(?BASE62:encode(10)), - 100 = ?BASE62:decode(?BASE62:encode(100)), - 9999 = ?BASE62:decode(?BASE62:encode(9999)), - 65535 = ?BASE62:decode(?BASE62:encode(65535)), + <<"10">> = ?BASE62:decode(?BASE62:encode(<<"10">>)), + <<"100">> = ?BASE62:decode(?BASE62:encode(<<"100">>)), + <<"9999">> = ?BASE62:decode(?BASE62:encode(<<"9999">>)), + <<"65535">> = ?BASE62:decode(?BASE62:encode(<<"65535">>)), <> = emqx_guid:gen(), <> = emqx_guid:gen(), - X = ?BASE62:decode(?BASE62:encode(X)), - Y = ?BASE62:decode(?BASE62:encode(Y)). + X = ?BASE62:decode(?BASE62:encode(X), integer), + Y = ?BASE62:decode(?BASE62:encode(Y), integer), + <<"helloworld">> = ?BASE62:decode(?BASE62:encode("helloworld")), + "helloworld" = ?BASE62:decode(?BASE62:encode("helloworld", string), string). +