Чем заменить if () else if() else if() else if() else if()..
От: korzhik Россия  
Дата: 18.08.04 05:55
Оценка:
Здравствуйте,

имею такой код:
  aux::tokenizer::token tk = m_tok.current_token();

  if (is_command(tk))
  {
    if (std::strncmp(tk.ptr, "#PAGE_PLOT", tk.len) == 0)
    {
      parse_page_plot_cmd();
    }
    else
    if (std::strncmp(tk.ptr, "#WELL", tk.len) == 0)
    {
      parse_well_cmd();
    }
    else
    if (std::strncmp(tk.ptr, "#PWDW", tk.len) == 0)
    {
      parse_pwdw_cmd();
    }
    else
    if ()
    // . . .
    // и дальше штук двадцать


и я вот думаю менять его или нет:
может заменить эту конструкцию на std::map
или ещё какой вариант, который вы мне здесь, я надеюсь, подскажете.
а может оставить как есть, в надежде что компилятор сделает подобие map за меня?
Re: Чем заменить if () else if() else if() else if() else if
От: Vamp Россия  
Дата: 18.08.04 06:00
Оценка:
В самом деле, представляется неплохой идеей иметь map, в котором ключами являются строки, а значениями — указатели на функции.
Тогда вместо ифов получается очень элегантно:

the_map[tk.ptr]();


Не ГИС часом пишешь?
Да здравствует мыло душистое и веревка пушистая.
Re: Чем заменить if () else if() else if() else if() else if
От: Lorenzo_LAMAS  
Дата: 18.08.04 06:07
Оценка: -1 :)))
Зверски вложенный ?: тебе поможет

is_command(tk) ? !std::strncmp(tk.ptr, "#PAGE_PLOT", tk.len) ? parse_page_plot_cmd() : !std::strncmp(tk.ptr, "#WELL", tk.len) ? parse_well_cmd() : .......


Главное чтоб типы, возвращаемые функциями подходили или явно их к void преобразовывать
Of course, the code must be complete enough to compile and link.
Re: Чем заменить if () else if() else if() else if() else if
От: IamLexa  
Дата: 18.08.04 06:08
Оценка: +1
Здравствуйте, korzhik, Вы писали:

K>Здравствуйте,


K>имею такой код:

K>
K>  aux::tokenizer::token tk = m_tok.current_token();

K>  if (is_command(tk))
K>  {
K>    if (std::strncmp(tk.ptr, "#PAGE_PLOT", tk.len) == 0)
K>    {
K>      parse_page_plot_cmd();
K>    }
K>    else
K>    if (std::strncmp(tk.ptr, "#WELL", tk.len) == 0)
K>    {
K>      parse_well_cmd();
K>    }
K>    else
K>    if (std::strncmp(tk.ptr, "#PWDW", tk.len) == 0)
K>    {
K>      parse_pwdw_cmd();
K>    }
K>    else
K>    if ()
K>    // . . .
K>    // и дальше штук двадцать
K>


K>и я вот думаю менять его или нет:

K>может заменить эту конструкцию на std::map
K>или ещё какой вариант, который вы мне здесь, я надеюсь, подскажете.
K>а может оставить как есть, в надежде что компилятор сделает подобие map за меня?

а я создаю массив типа
struct ComandInfo {
   const char* name;
   void (*handler) ();
};
static const CommandInfo COMMANDS [] = {
   { "#PAGE_PLOT", &parse_page_plot_cmd },
   ...
};

for (int i = 0; i != ARRAY_SIZE (COMMANDS); ++i) {
   if (strncmp (COMMANDS [i].name, tk.ptr) == 0) {
      COMMANDS [i].handler ();
      break;
   }
}
Re: Чем заменить if () else if() else if() else if() else if
От: Lloyd Россия  
Дата: 18.08.04 06:09
Оценка: -1
Здравствуйте, korzhik, Вы писали:

K>и я вот думаю менять его или нет:

K>может заменить эту конструкцию на std::map
K>или ещё какой вариант, который вы мне здесь, я надеюсь, подскажете.
K>а может оставить как есть, в надежде что компилятор сделает подобие map за меня?

Почитай про паттерн state. Возможно, он тебе подойдет.
Re[2]: Чем заменить if () else if() else if() else if() else
От: Vamp Россия  
Дата: 18.08.04 06:12
Оценка:
оффтоп.
Ллойд пхнул минус тебе, ты ллойду. А разъяснить за что?
Да здравствует мыло душистое и веревка пушистая.
Re[2]: Чем заменить if () else if() else if() else if() else
От: korzhik Россия  
Дата: 18.08.04 06:13
Оценка:
Здравствуйте, Vamp, Вы писали:

V>В самом деле, представляется неплохой идеей иметь map, в котором ключами являются строки, а значениями — указатели на функции.

V>Тогда вместо ифов получается очень элегантно:

V>
V>the_map[tk.ptr]();
V>


что элегантно это конечно хорошо, но карту(std::map) ещё заполнить надо:
parser::parser()
{
  m_handlers_map["#PAGE_PLOT"] = &parse_page_plot_cmd();
  m_handlers_map["#WELL"]      = &parse_well_cmd();
  m_handlers_map["#PWDW"]      = &parse_pwdw_cmd();
  // . . .
}

void parser::parse_line(const char* line)
{
  m_tok.set_str(line);

  if (m_tok.next())
  {
    aux::tokenizer::token tk = m_tok.current_token();

    if (is_command(tk))
    {
      the_map[std::string(tk.ptr, tk.len)]();
    }
  }
}

получается конечно красивее, наверно так и переделаю, но меня больше в этом вопросе волнует скорость.
То есть сможет ли компилятор в случае if else if else... сам составить карту?

V>Не ГИС часом пишешь?

скажем так, дорабатываю
Re[2]: Чем заменить if () else if() else if() else if() else
От: korzhik Россия  
Дата: 18.08.04 06:16
Оценка:
Здравствуйте, IamLexa, Вы писали:

IL>а я создаю массив типа

IL>
IL>struct ComandInfo {
IL>   const char* name;
IL>   void (*handler) ();
IL>};
IL>static const CommandInfo COMMANDS [] = {
IL>   { "#PAGE_PLOT", &parse_page_plot_cmd },
IL>   ...
IL>};

IL>for (int i = 0; i != ARRAY_SIZE (COMMANDS); ++i) {
IL>   if (strncmp (COMMANDS [i].name, tk.ptr) == 0) {
IL>      COMMANDS [i].handler ();
IL>      break;
IL>   }
IL>}
IL>


в этом случае я бы пользовался std::map, быстрее обработчик искать будет.
Re: Чем заменить if () else if() else if() else if() else if
От: MaximE Великобритания  
Дата: 18.08.04 06:16
Оценка: 5 (4)
korzhik wrote:

> Здравствуйте,

>
> имею такой код:
>
>   aux::tokenizer::token tk = m_tok.current_token();
>
>   if (is_command(tk))
>   {
>     if (std::strncmp(tk.ptr, "#PAGE_PLOT", tk.len) == 0)
>     {
>       parse_page_plot_cmd();
>     }
>     else
>     if (std::strncmp(tk.ptr, "#WELL", tk.len) == 0)
>     {
>       parse_well_cmd();
>     }
>     else
>     if (std::strncmp(tk.ptr, "#PWDW", tk.len) == 0)
>     {
>       parse_pwdw_cmd();
>     }
>     else
>     if ()
>     // . . .
>     // и дальше штук двадцать
>

>
> и я вот думаю менять его или нет:
> может заменить эту конструкцию на std::map
> или ещё какой вариант, который вы мне здесь, я надеюсь, подскажете.
> а может оставить как есть, в надежде что компилятор сделает подобие map за меня?

Надежды, я думаю, нет.

Если бы мне нужен был бы absolute raw perfomance, я бы посчитал хэши для твоих контсант ("#PAGE_PLOT", "#WELL"), подобрав такую хэш ф-цию, чтобы хэши по модулю N для всех констант были уникальными. Далее я бы использовал массив[N] указателей на ф-ции.

typedef void(function_t)();
function_t* functions[N];
// ...
if(is_command(tk))
{
     size_t const h(hash(tk));
     if(h < N)
         functions[h]();
}


--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 beta
Re[3]: Чем заменить if () else if() else if() else if() else
От: Lloyd Россия  
Дата: 18.08.04 06:16
Оценка:
Здравствуйте, Vamp, Вы писали:

V>оффтоп.

V>Ллойд пхнул минус тебе, ты ллойду. А разъяснить за что?

Он видимо пнул мне за то, что я ему пнул. Учили видимо в детстве стоять за себя.

Я поставил минус потому что считаю, что вариант, предложенный Lorenzo_LAMAS-ом обладает как плохой читаемостью, так и плохой сопровождаемостью. И при этом ни одним преимуществом перед первоначальным вариантом не обладает.
Re[4]: Чем заменить if () else if() else if() else if() else
От: Lorenzo_LAMAS  
Дата: 18.08.04 06:18
Оценка: :))
L>Он видимо пнул мне за то, что я ему пнул. Учили видимо в детстве стоять за себя.

Ты правильно понял.
Of course, the code must be complete enough to compile and link.
Re[4]: Чем заменить if () else if() else if() else if() else
От: korzhik Россия  
Дата: 18.08.04 06:21
Оценка: +2
Здравствуйте, Lloyd, Вы писали:

L>Я поставил минус потому что считаю, что вариант, предложенный Lorenzo_LAMAS-ом обладает как плохой читаемостью, так и плохой сопровождаемостью.


да он же пошутил.
Re[3]: Чем заменить if () else if() else if() else if() else
От: IamLexa  
Дата: 18.08.04 06:27
Оценка:
Здравствуйте, korzhik, Вы писали:

K>Здравствуйте, IamLexa, Вы писали:


IL>>а я создаю массив типа

IL>>
IL>>struct ComandInfo {
IL>>   const char* name;
IL>>   void (*handler) ();
IL>>};
IL>>static const CommandInfo COMMANDS [] = {
IL>>   { "#PAGE_PLOT", &parse_page_plot_cmd },
IL>>   ...
IL>>};

IL>>for (int i = 0; i != ARRAY_SIZE (COMMANDS); ++i) {
IL>>   if (strncmp (COMMANDS [i].name, tk.ptr) == 0) {
IL>>      COMMANDS [i].handler ();
IL>>      break;
IL>>   }
IL>>}
IL>>


K>в этом случае я бы пользовался std::map, быстрее обработчик искать будет.


а где-то было сказано, что надо быстрее?
использование std::map -- это вопрос оптимизации.
я тоже могу придумать ситуацию, когда std::map() для такой задачи будет не лучшим вариантом.
Re[2]: Чем заменить if () else if() else if() else if() else
От: korzhik Россия  
Дата: 18.08.04 06:31
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Если бы мне нужен был бы absolute raw perfomance, я бы посчитал хэши для твоих контсант ("#PAGE_PLOT", "#WELL"), подобрав такую хэш ф-цию, чтобы хэши по модулю N для всех констант были уникальными. Далее я бы использовал массив[N] указателей на ф-ции.


хорошая мысль. Будет свободное время, может сделаю.
Re[3]: Чем заменить if () else if() else if() else if() else
От: Vamp Россия  
Дата: 18.08.04 06:32
Оценка:
K>что элегантно это конечно хорошо, но карту(std::map) ещё заполнить надо:
Естественно.

K>получается конечно красивее, наверно так и переделаю, но меня больше в этом вопросе волнует скорость.

K>То есть сможет ли компилятор в случае if else if else... сам составить карту?
Не знаю. Я бы на это не особо рассчитывал. Если хочешь скорости — составь не карту, а хэш-таблицу. Обеспечишь вызов функции за константное время.

V>>Не ГИС часом пишешь?

K>скажем так, дорабатываю
Похоже на парсер las-файлов. Сам когда-то этим занимался.
Да здравствует мыло душистое и веревка пушистая.
Re[4]: Чем заменить if () else if() else if() else if() else
От: korzhik Россия  
Дата: 18.08.04 06:35
Оценка:
Здравствуйте, IamLexa, Вы писали:

K>>в этом случае я бы пользовался std::map, быстрее обработчик искать будет.


IL>а где-то было сказано, что надо быстрее?

IL>использование std::map -- это вопрос оптимизации.
правильно, вопрос оптимизации.
предложенный тобой вариант аналогичен использованию std::map, только std::map быстрее будет выполнять поиск.
Вот я тебе об этом и написал.

ЗЫ
Всё равно спасибо за участие в дискуссии.
Re[4]: Чем заменить if () else if() else if() else if() else
От: korzhik Россия  
Дата: 18.08.04 06:40
Оценка:
Здравствуйте, Vamp, Вы писали:

K>>То есть сможет ли компилятор в случае if else if else... сам составить карту?

V>Не знаю. Я бы на это не особо рассчитывал. Если хочешь скорости — составь не карту, а хэш-таблицу. Обеспечишь вызов функции за константное время.
пока сделаю std::map,
будет время подумаю над хэш-функцией

V>>>Не ГИС часом пишешь?

K>>скажем так, дорабатываю
V>Похоже на парсер las-файлов. Сам когда-то этим занимался.
с las'ами я тоже работаю, но сейчас это не las, а внутренний формат.
Re: Чем заменить if () else if() else if() else if() else if
От: Batiskaf Израиль http://www.mult.ru/
Дата: 18.08.04 06:43
Оценка: +1
Здравствуйте, korzhik, Вы писали:

K>Здравствуйте,


K>имею такой код:

K>
K>  aux::tokenizer::token tk = m_tok.current_token();

K>  if (is_command(tk))
K>  {
K>    if (std::strncmp(tk.ptr, "#PAGE_PLOT", tk.len) == 0)
K>    {
K>      parse_page_plot_cmd();
K>    }
K>    else
K>    if (std::strncmp(tk.ptr, "#WELL", tk.len) == 0)
K>    {
K>      parse_well_cmd();
K>    }
K>    else
K>    if (std::strncmp(tk.ptr, "#PWDW", tk.len) == 0)
K>    {
K>      parse_pwdw_cmd();
K>    }
K>    else
K>    if ()
K>    // . . .
K>    // и дальше штук двадцать
K>


K>и я вот думаю менять его или нет:

K>может заменить эту конструкцию на std::map
K>или ещё какой вариант, который вы мне здесь, я надеюсь, подскажете.
K>а может оставить как есть, в надежде что компилятор сделает подобие map за меня?

Только хотел предложить решение с хешами, да вот заметил пост Макса... Действительное, самое хорошее решение с точки зрения производительности, значительно лучше мапа. В строчном мапе каждый раз прийдется делать сравнение строк, в случае хеша ты только раз хешируешь входную строку и делаешь разрешение индекса на указатель на функцию, значительно дешевле. А заполнять массив не обязательно каждый раз в конструкторе, этот массив можно сделать статическим, он по логике не связан с конкретным инстансом твоего парсера.
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re[2]: Чем заменить if () else if() else if() else if() else
От: achmed Удмуртия https://www.linkedin.com/in/nail-achmedzhanov-9907188/
Дата: 18.08.04 06:55
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Здравствуйте, korzhik, Вы писали:


K>>и я вот думаю менять его или нет:

K>>может заменить эту конструкцию на std::map
K>>или ещё какой вариант, который вы мне здесь, я надеюсь, подскажете.
K>>а может оставить как есть, в надежде что компилятор сделает подобие map за меня?

L>Почитай про паттерн state. Возможно, он тебе подойдет.

а при чем здесь state, может быть command ?
Re: Чем заменить if () else if() else if() else if() else if
От: Кодт Россия  
Дата: 18.08.04 07:37
Оценка:
Здравствуйте, korzhik, Вы писали:

K>имею такой код:

K>
K>  aux::tokenizer::token tk = m_tok.current_token();

K>  if (is_command(tk))
K>  {
K>    if (std::strncmp(tk.ptr, "#PAGE_PLOT", tk.len) == 0)
K>    {
K>      parse_page_plot_cmd();
K>    }
K>    else
K>    if (std::strncmp(tk.ptr, "#WELL", tk.len) == 0)
K>    {
K>      parse_well_cmd();
K>    }
K>    else
K>    if (std::strncmp(tk.ptr, "#PWDW", tk.len) == 0)
K>    {
K>      parse_pwdw_cmd();
K>    }
K>    else
K>    if ()
K>    // . . .
K>    // и дальше штук двадцать
K>


Во-первых, strncmp
inline int compare(const aux::tokenizer::token& tk, const char* s)
{
  return std::strncmp(tk.ptr, s, tk.len);
}

Во-вторых, можно родить (сортированный) контейнер с хитрым предикатом
struct less_token
{
  typedef aux::tokenizer::token token;

  bool operator()(const char* lhs, const char* rhs) const { return strcmp(lhs,rhs)<0; }
  bool operator()(const token& lhs, const char* rhs) const { return compare(lhs,rhs)<0; }
  bool operator()(const char* lhs, const token& rhs) const { return compare(rhs,lhs)>0; }
};
struct match_token
{
  typedef aux::tokenizer::token token;

  bool operator()(const char* lhs, const char* rhs) const { return strcmp(lhs,rhs)==0; }
  bool operator()(const token& lhs, const char* rhs) const { return compare(lhs,rhs)==0; }
  bool operator()(const char* lhs, const token& rhs) const { return compare(rhs,lhs)==0; }
};

Сам контейнер может быть простым массивом
typedef std::pair<const char*, void (YourClass::*)()> command_entry;

const command_entry commands[] =
{
  std::make_pair("#PAGE_PLOT", &YourClass::parse_page_plot_cmd),
  std::make_pair("#WELL",      &YourClass::parse_well_cmd),
  ...
};
const size_t commands_count = sizeof(commands)/sizeof(commands[0]);
const command_entry* commands_end = commands + commands_count;

struct match_command
{
  bool operator()(const command_entry& lhs, const token& rhs) const { return compare(rhs, lhs.first) == 0; }
};

YourClass::parse()
{
  aux::tokenizer::token tk = m_tok.current_token();
  command_entry* cmd = std::find_if(commands, commands_end, tk, match_command());
  if(cmd != commands_end)
    (this->*(cmd->second))();
}
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.