Приветствую всех! Попросите вашу маму налить вам немного борща и зацените мою кулстори. Мы как-то обсуждали с monk полезность eval в common lisp. Для меня, так вещь не особо нужная и мало используемая (как и некоторые другие конструкции языка, впрочем). А он мне привел пример генерации кода на лету для некоторого подмножества входных данных, где этот код проще, чем для полного набора.
И я подумал, а почему бы не сделать так же? Вот тут на C есть кусок кода (из libFLAC), в котором разворачивается следующий цикл:
/* Here's a slower but clearer version:
for(i = 0; i < data_len; i++) {
sum = 0;
for(j = 0; j < order; j++)
sum += qlp_coeff[j] * data[i-j-1];
residual[i] = data[i] - (sum >> lp_quantization);
}
*/
для всех допустимых значений order - это [1; 32]. Причем самые часто используемые значения [1;12], входящие в так называемое подмножество FLAC расставлены там так, чтобы к самым вероятным значениям order шло как можно меньше ветвлений.
Сначала я сделал на CL то же самое, заменив разве что блоки вида
sum += qlp_coeff[j] * data[i-j-1];
...
sum += qlp_coeff[0] * data[i-1];
А потом подумал, может можно сделать это элегантней? И решил для каждого значения order сделать отдельную функцию, поместить их в заготовленную хеш-таблицу, а потом вызывать их оттуда. А для тех значений order, которые не встречаются в подможестве, генерировать функцию «на лету» и добавлять в таблицу.
В итоге получилось такая любопытная штука:
По длине в 4 раза короче сишной.
Но тут я посчитал скорость выполнения этого дела и прямо таки не почувствовал никакой разницы. Причем пересобрал libLFAC с утилитами без разворачивания цикла и тоже не увидел разницы. Ну и ладно, зато в профайлере можно смотреть статистику про порядкам, подумал я и оставил такой выкрутасный вариант.
А как вы считаете, нужен ли eval? Можете ли вы сделать раскрутку цикла в runtime на вашем любимом ЯП? Дискач.