2016-03-28 6 views
0

Also schrieb ich zwei Versionen eines gen_fsm, um einen Byte-Stream zu parsen. Ich suche nach einem Paket, das mit der Zeichenfolge snp beginnt und dann möchte ich die nächsten 20 Bytes nach der p speichern. Dieser Code betrifft nur den Header. Ich brauche einen Ratschlag, welcher idiomatischer Erlang besser ist oder ein besserer Weg, um ihn zu schreiben.Was ist idiomatischer?

Option 1

parse_header({parse, Byte}, {Header, [Next | Rest]}) -> 
    case Byte of 
    Next when length(Rest) > 0 -> {next_state, parse_header, {Header, Rest}}; 
    Next when length(Rest) == 0 -> {next_state, parse_data, []}; 
    $s  -> parse_header({parse, Byte}, {Header, Header}); 
    _   -> {next_state, parse_header, {Header, Header}} 
end. 

Option 2

parse_start({parse, Byte}, State) when Byte == $s -> 
    {next_state, parse_new, State}; 
parse_start({parse, Byte}, State) when Byte /= $s -> 
    {next_state, parse_start, State}. 

parse_new({parse, Byte}, State) when Byte == $n -> 
    {next_state, parse_packet, State}; 
parse_new({parse, Byte}, State) when Byte == $s -> 
    parse_start({parse, Byte}, State); 
parse_new({parse, _Byte}, State) -> 
    {next_state, parse_start, State}. 

parse_packet({parse, Byte}, State) when Byte == $p -> 
    {next_state, parse_data, State}; 
parse_packet({parse, Byte}, State) when Byte == $s -> 
    parse_start({parse, Byte}, State); 
parse_packet({parse, _Byte}, State) -> 
    {next_state, parse_start, State}. 

Antwort

1

Beide Ausführungen sind in Ordnung, aber Sie sollten eine Implementierung bevorzugen, die Ausflüge in die gen_fsm Schleife minimiert, analysiert somit die Daten erschöpfend bis nichts mehr zu analysieren ist und erst dann die Kontrolle wieder an gen_fsm zurückgegeben wird.

Also wäre die erste Implementierung in dieser Hinsicht besser. Auch eine kürzere Implementierung ist in der Regel einfacher zu überdenken, also wieder ein Punkt für die erste Lösung.

Allerdings ist die zweite Implementierung (wohl) klarer und besser passt ein gen_fsm Ansatz, so wäre wahrscheinlich einfacher zu pflegen und zu erweitern, wenn nötig.

Vielleicht könnten Sie eine Lösung finden, die die besten Teile von beiden nimmt? Zum Beispiel, wie etwa diese:

parse_header([ $s, $n, $p | Rest]) -> copy_data(Rest, 20, []); 
parse_header([ _ | T ]) -> parse_header(T); 
parse_header(List) when length(List) < 3 -> {next_state, parse_header}. 

copy_data(_, 0, Acc) -> lists:reverse(Acc); 
copy_data([], X, Acc) -> {next_state, {copy_data, X, Acc}}; 
copy_data([H | T], X, Acc) -> copy_data(T, X - 1, [H | Acc]). 

Es wird versucht, den Eingang erschöpfend zu lesen und nur gibt die Kontrolle zurück zu gen_fsm, wenn keine Daten mehr zu lesen sind. Und wie in der zweiten Lösung trennt es das Parsen des Headers vom Lesen der Daten.

Das ist natürlich nur ein Beispiel, wie das Problem angegangen werden könnte, weil ich nicht den Rest von Ihnen Code noch Ihre genauen Anforderungen kenne.

Verwandte Themen