Просмотр исходного кода

Enhance base62 encode/decode Funs

Gilbert Wong 7 лет назад
Родитель
Сommit
79481db659
3 измененных файлов с 86 добавлено и 40 удалено
  1. 77 32
      src/emqx_base62.erl
  2. 3 2
      src/emqx_guid.erl
  3. 6 6
      test/emqx_base62_SUITE.erl

+ 77 - 32
src/emqx_base62.erl

@@ -16,41 +16,86 @@
 
 
 -export([encode/1, decode/1]).
 -export([encode/1, decode/1]).
 
 
-%% @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, [])).
 
 
-encode(I, Acc) when I < 62 ->
-    [char(I) | Acc];
-encode(I, Acc) ->
-    encode(I div 62, [char(I rem 62) | Acc]).
+%% @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, <<>>).
 
 
-char(I) when I < 10 ->
-    $0 + I;
+%% @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(B, <<>>).
 
 
-char(I) when I < 36 ->
-    $A + I - 10;
+%% encode_base62(<<H:24, Rest/binary>>, Acc) ->
+%%     encode_byte_group(H, Acc);
+%% encode_base62(<<H:16, Rest/binary>>, Acc) ->
+%%     encode_byte_group(H, Acc);
 
 
-char(I) when I < 62 ->
-    $a + I - 36.
 
 
-%% @doc Decode base62 string to an integer
--spec(decode(string() | binary()) -> integer()).
-decode(B) when is_binary(B) ->
-    decode(binary_to_list(B));
-decode(S) when is_list(S) ->
-    decode(S, 0).
-
-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.
+encode(<<Index1:6, Index2:6, Index3:6, Index4:6, Rest/binary>>, Acc) ->
+    CharList = [encode_char(Index1), encode_char(Index2), encode_char(Index3), encode_char(Index4)],
+    NewAcc = <<Acc/binary,(iolist_to_binary(CharList))/binary>>,
+    encode(Rest, NewAcc);
+encode(<<Index1:6, Index2:6, Index3:4>>, Acc) ->
+    CharList = [encode_char(Index1), encode_char(Index2), encode_char(Index3)],
+    NewAcc = <<Acc/binary,(iolist_to_binary(CharList))/binary>>,
+    encode(<<>>, NewAcc);
+encode(<<Index1:6, Index2:2>>, Acc) ->
+    CharList = [encode_char(Index1), encode_char(Index2)],
+    NewAcc = <<Acc/binary,(iolist_to_binary(CharList))/binary>>,
+    encode(<<>>, NewAcc);
+encode(<<>>, Acc) ->
+    Acc.
+
+decode(<<Head:8, Rest/binary>>, Acc)
+  when bit_size(Rest) >= 8->
+    case Head == $9 of
+        true ->
+            <<Head1:8, Rest1/binary>> = Rest,
+            DecodeChar = decode_char(9, Head1),
+            <<_:2, RestBit:6>> = <<DecodeChar>>,
+            NewAcc = <<Acc/bitstring, RestBit:6>>,
+            decode(Rest1, NewAcc);
+        false ->
+            DecodeChar = decode_char(Head),
+            <<_:2, RestBit:6>> = <<DecodeChar>>,
+            NewAcc = <<Acc/bitstring, RestBit:6>>,
+            decode(Rest, NewAcc)
+    end;
+decode(<<Head:8, Rest/binary>>, Acc) ->
+    DecodeChar = decode_char(Head),
+    LeftBitSize = bit_size(Acc) rem 8,
+    RightBitSize = 8 - LeftBitSize,
+    <<_:LeftBitSize, RestBit:RightBitSize>> = <<DecodeChar>>,
+    NewAcc = <<Acc/bitstring, RestBit:RightBitSize>>,
+    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.

+ 3 - 2
src/emqx_guid.erl

@@ -126,8 +126,9 @@ from_hexstr(S) ->
     I = list_to_integer(binary_to_list(S), 16), <<I:128>>.
     I = list_to_integer(binary_to_list(S), 16), <<I:128>>.
 
 
 to_base62(<<I:128>>) ->
 to_base62(<<I:128>>) ->
-    emqx_base62:encode(I).
+    binary_to_list(emqx_base62:encode(I)).
 
 
 from_base62(S) ->
 from_base62(S) ->
-    I = emqx_base62:decode(S), <<I:128>>.
+    I = binary_to_integer(emqx_base62:decode(S)),
+    <<I:128>>.
 
 

+ 6 - 6
test/emqx_base62_SUITE.erl

@@ -26,11 +26,11 @@
 all() -> [t_base62_encode].
 all() -> [t_base62_encode].
 
 
 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">>)),
     <<X:128/unsigned-big-integer>> = emqx_guid:gen(),
     <<X:128/unsigned-big-integer>> = emqx_guid:gen(),
     <<Y:128/unsigned-big-integer>> = emqx_guid:gen(),
     <<Y:128/unsigned-big-integer>> = emqx_guid:gen(),
-    X = ?BASE62:decode(?BASE62:encode(X)),
-    Y = ?BASE62:decode(?BASE62:encode(Y)).
+    X = erlang:binary_to_integer(?BASE62:decode(?BASE62:encode(X))),
+    Y = erlang:binary_to_integer(?BASE62:decode(?BASE62:encode(Y))).