perf(topic): use tail recursive to joining a topic

This commit is contained in:
JimMoen 2023-06-07 16:30:18 +08:00
parent b0e18f5e75
commit 4ea3483083
No known key found for this signature in database
GPG Key ID: 87A520B4F76BA86D
2 changed files with 21 additions and 16 deletions

View File

@ -39,6 +39,11 @@
-type word() :: emqx_types:word(). -type word() :: emqx_types:word().
-type words() :: emqx_types:words(). -type words() :: emqx_types:words().
%% Guards
-define(MULTI_LEVEL_WILDCARD_NOT_LAST(C, REST),
((C =:= '#' orelse C =:= <<"#">>) andalso REST =/= [])
).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% APIs %% APIs
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
@ -110,7 +115,8 @@ validate2([]) ->
% end with '#' % end with '#'
validate2(['#']) -> validate2(['#']) ->
true; true;
validate2(['#' | Words]) when length(Words) > 0 -> %% MQTT-5.0 [MQTT-4.7.1-1]
validate2([C | Words]) when ?MULTI_LEVEL_WILDCARD_NOT_LAST(C, Words) ->
error('topic_invalid_#'); error('topic_invalid_#');
validate2(['' | Words]) -> validate2(['' | Words]) ->
validate2(Words); validate2(Words);
@ -213,20 +219,16 @@ feed_var(Var, Val, [W | Words], Acc) ->
-spec join(list(word())) -> binary(). -spec join(list(word())) -> binary().
join([]) -> join([]) ->
<<>>; <<>>;
join([W]) -> join([Word | Words]) ->
bin(W); do_join(bin(Word), Words).
join(Words) ->
{_, Bin} = lists:foldr( do_join(TopicAcc, []) ->
fun TopicAcc;
(W, {true, Tail}) -> %% MQTT-5.0 [MQTT-4.7.1-1]
{false, <<W/binary, Tail/binary>>}; do_join(_TopicAcc, [C | Words]) when ?MULTI_LEVEL_WILDCARD_NOT_LAST(C, Words) ->
(W, {false, Tail}) -> error('topic_invalid_#');
{false, <<W/binary, "/", Tail/binary>>} do_join(TopicAcc, [Word | Words]) ->
end, do_join(<<TopicAcc/binary, "/", (bin(Word))/binary>>, Words).
{true, <<>>},
[bin(W) || W <- Words]
),
Bin.
-spec parse(topic() | {topic(), map()}) -> {topic(), #{share => binary()}}. -spec parse(topic() | {topic(), map()}) -> {topic(), #{share => binary()}}.
parse(TopicFilter) when is_binary(TopicFilter) -> parse(TopicFilter) when is_binary(TopicFilter) ->

View File

@ -199,7 +199,10 @@ t_join(_) ->
?assertEqual(<<"+//#">>, join(['+', '', '#'])), ?assertEqual(<<"+//#">>, join(['+', '', '#'])),
?assertEqual(<<"x/y/z/+">>, join([<<"x">>, <<"y">>, <<"z">>, '+'])), ?assertEqual(<<"x/y/z/+">>, join([<<"x">>, <<"y">>, <<"z">>, '+'])),
?assertEqual(<<"/ab/cd/ef/">>, join(words(<<"/ab/cd/ef/">>))), ?assertEqual(<<"/ab/cd/ef/">>, join(words(<<"/ab/cd/ef/">>))),
?assertEqual(<<"ab/+/#">>, join(words(<<"ab/+/#">>))). ?assertEqual(<<"ab/+/#">>, join(words(<<"ab/+/#">>))),
%% MQTT-5.0 [MQTT-4.7.1-1]
?assertError('topic_invalid_#', join(['+', <<"a">>, '#', <<"b">>, '', '+'])),
?assertError('topic_invalid_#', join(['+', <<"c">>, <<"#">>, <<"d">>, '', '+'])).
t_systop(_) -> t_systop(_) ->
SysTop1 = iolist_to_binary(["$SYS/brokers/", atom_to_list(node()), "/xyz"]), SysTop1 = iolist_to_binary(["$SYS/brokers/", atom_to_list(node()), "/xyz"]),