2016-03-28 3 views
0

Итак, я написал две версии gen_fsm для синтаксического анализа байтового потока. Я ищу пакет, который начинается со строки snp, а затем я хочу сохранить следующие 20 байт после p. Этот код просто касается поиска заголовка. Мне нужен совет, по которому более идиоматический Эрланг или лучший способ его написать.Что более идиоматично?

Вариант 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. 

Вариант 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}. 

ответ

1

Обе реализации отлично, однако вы должны предпочесть реализацию, которая сводит к минимуму поездки в петлю gen_fsm, таким образом анализирует данные исчерпывающе пока нет ничего другого, чтобы разобрать и только затем возвращает управление gen_fsm.

Таким образом, первая реализация была бы лучше в этом отношении. Кроме того, более короткая реализация, как правило, легче рассуждать, поэтому снова точка для первого решения.

Однако вторая реализация (возможно) более ясная и лучше подходит подходу gen_fsm, поэтому, вероятно, будет легче поддерживать и расширять, если необходимо.

Возможно, вы нашли бы решение, в котором будут взяты лучшие части от обоих? Например, как об этом один:

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]). 

Он пытается читать ввод исчерпывающе и только возвращает управление обратно gen_fsm если нет больше данных для чтения. И, как во втором решении, он отделяет разбор заголовка от чтения данных.

Это, конечно, только пример того, как к проблеме можно подойти, потому что я не знаю остального кода и ваших точных требований.