Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
static inline unsigned char test_predicate_12(struct T_cash_account_row const*const __restrict row, struct T_range_filters const*const __restrict range_filters)
{
const char p0 = (row->age - range_filters->begin.age) <= (range_filters->end.age - range_filters->begin.age);
const char p1 = (row->code - range_filters->begin.code) <= (range_filters->end.code - row->begin.code);
return p0 & p1;
}static inline size_t search_12(struct T_cash_account_row const*const __restrict array_ptr, const size_t c_array_size, struct T_cash_account_row *const __restrict result_ptr, struct T_range_filters const*const __restrict range_filters)
{
size_t result_size = 0;
size_t i; /* loop index */
for(i = 0; i < c_array_size; ++i) {
result_ptr[result_size] = array_ptr[i];
result_size += test_predicate_12(array_ptr + i, range_filters);
}
return result_size;
}Неплохо, но есть небольшая проблемка – C-разработчикам придется вручную создать эти 32 функции, нигде в них не ошибиться перебирая все варианты и при любом изменении числа и имен полей менять нужные функции.В С есть макросы и инлайновые функции, так что не все так плохо, как вы пытаетесь показать.
В С есть макросы и инлайновые функции, так что не все так плохо, как вы пытаетесь показать.
Также я бы хотел увидеть красивое решение для инициализации массива с 32 специализированными функциями поиска, для выбора оптимальной реализации в рантайме.
Также, интересны какой эффект будет при отказе от битфилдов.
Что значит есть инлайновые функции, как будто я их здесь не использовал при сравнении?Подумайте, как инлайновые функции можно использовать в задаче кодогенерации (подсказка: устранение константных выражений при оптимизации).
Ну, а использовать макросы вместо шаблонов, что зря теоретизировать, приведите решение на них и вы увидите почему так делать нельзя никогда.
Если вам не лень писать 32 специализированных функций на C, выкладывайте пример. А потом вам вдруг приходит задача добавить 2 поля, и вы пишите уже 128 функций :)Я не собираюсь вам ничего доказывать. Это вы тут доказываете превосходство C++, а мне такая постановка вопроса кажется скучной — для разных задач я использую и Си и C++ и еще штук пять других языков. На случай, если вы считаете всех собеседников по умолчанию идиотами, прошу ознакомиться.
Также, интересны какой эффект будет при отказе от битфилдов.Это оффтопик. Но что вам мешает попробовать?
Подумайте, как инлайновые функции можно использовать в задаче кодогенерации (подсказка: устранение константных выражений при оптимизации).
я использую и Си и C++ и еще штук пять других языков
Ответ не в тему. Подумайте-подумайте, гуру шаблонов вы наш.Подумайте, как инлайновые функции можно использовать в задаче кодогенерации (подсказка: устранение константных выражений при оптимизации).Вы у меня видели не inline функции, кроме main() и тех, что должны быть виртуальными?
Только вы могли придумать использовать для скоростного поиска строки аллоцируемые отдельно от элемента.Ну-ну успокойтесь же) Представьте, что у вас два строковых поля, как бы вы их не стали хранить, без кеш-промаха тут не обойдется.
Разница в том, что мой аргумент рабочий пример и результат тестов, а ваш аргумент, что вам скучно. И от скуки пишите что попало.
Только вы могли придумать использовать для скоростного поиска строки аллоцируемые отдельно от элемента.
Ну-ну успокойтесь же) Представьте, что у вас два строковых поля, как бы вы их не стали хранить, без кеш-промаха тут не обойдется.
Куда уж мне до вас знающего C, C++ и ещё 5 языков программирования.У меня еще и ВО есть)
стати, то, что компилятор «просто падает» на каком-либо коде — это камень в первую очередь в огород компилятора. И не просто камень, а здоровенный булыжник. Даже если код написан с нарушением всех мыслимых и немыслимых стандартов, компилятор падать не должен.
Вы бы куда меньше времени потратили на написание своего правильного теста, чем на голые комментарии с пустой критикой.
«Я не собираюсь вам ничего доказывать. Это вы тут доказываете превосходство C++» — да, он доказывает превосходство С++ на данной конкретной задаче, и у него есть на это основания — конкретный тест. Если вы хотите опровергать — опровергайте предметно, а не «я знаю лучше, вот тут будет так-то и так-то, но доказывать ничего не собираюсь». Это на опровержение ну никак не тянет.
from itertools import permutations as p
from math import pow
fields = ['','code','gender','age','amount_of_money','height']
def field_list_to_index(fl):
return sum(fields.index(i)*int(pow(len(fields),n)) for n,i in enumerate(fl))
for params in set(fl[:fl.index('')] for fl in p(fields) if fl[0]):
index = field_list_to_index(params)
print 'BEGINF(%s)'%index
print '\n'.join(' COMPAR(%s)'%p for p in params)
print 'ENDF(%s)'%index
BEGINF(377)
COMPAR(height)
COMPAR(gender)
COMPAR(amount_of_money)
COMPAR(code)
ENDF(377)
BEGINF(31)
COMPAR(code)
COMPAR(height)
ENDF(31)
К слову, эта оптимизация не применима в Java и C#, т.к. в generics невозможно использовать параметром значение, а не тип.
Ради справедливости стоит отметить, что в том же C# можно довольно легко средствами фреймфорка сгенерировать код фильтра во время исполнения и запускать вариант с нужным набором проверок.
Во-первых, компиляция на ходу приводит к ощутимым задержкам, поэтому не во всех случаях удобна.
Во-вторых, построение кода на Expression'ах — это тоже нехилые простыни, которые в подходе write-only составят достойную конкуренцию коду на шаблонах из соседнего топика.
Я бы трижды подумал, прежде чем внедрять в реальный проект такое шаманство.
C# может легко перемещать блоки памяти, снижая фрагментацию. С++ после активной работы с памятью будет сидеть с фрагментированной кучей…
Но Google C++ Style Guide рекомендует передавать неизменяемые параметры по константной ссылке const&, а изменяемые по константному указателю *const
const T*, а не о T* const ??const T*, тогда как в статье говорится о том, что Google C++ Style Guide рекомендует «константный указатель *const», т.е. T* const, что не одно и тоже. Смысл говорить об одном и давать ссылку на немножко другое? Ладно, не столь важно, статья не об этом.const T*? Другое дело, что в Google C++ Style Guide я вообще не нашел раздела про указатели.T* или T* constT* const Google C++ Style Guide не говорит.const T* — имелось в виду, что Google C++ Style Guide если уж и что-то говорит о передаче параметров — то только о const T*, а не о T* const (или const T* const).int x = 5;
foo(x);
cout << x;
Назовите-ка, что он выведет, не глядя на объявление foo, скрытое черт знает в каком заголовочном файле?Неоднократно замечал, что при проэктировинии баз данных поле «пол» делают булевым. При чем «true» означает мужской пол, а «false» — женский.
bash.im/quote/396500
unsigned gender:1;
Помимо этого, даже, существуют статьи показывающие преимущества в скорости языков с компиляцией налету (JIT — Just-in-time compilation), таких как Java и C#. Сравнить последние мы оставим тем, кто считает их быстрыми, но мы объясним почему это не такНебольшой пример, использующий динамическую генерацию кода и JIT: Ищем на java, оптимизация во время исполнения. За счет генераци «плана исполнения запроса» на лету и JIT, скорость получилась сравнимая со статической оптимизацией.
Но в C, где нет ссылок, такой подход не возможен, т.к. если функция всегда принимает только по указателю, то на стороне вызывающего нельзя гарантировать невозможность их модификации
void func(int const *a, int *b) {}*(int *)a = 0(int&)a = 0на стороне вызывающего нельзя гарантировать невозможность их модификации
void func(int const& a, int *b) {}
int a, b; func(a, &b);
int a, b; func(&a, &b);
/* Compare row with filters */
#define DECLARE(use_amount_of_money, use_gender, use_age) \
static inline unsigned char test_predicate_ ## use_amount_of_money ## _ ## use_gender ## _ ## use_age(struct T_cash_account_row const*const row, \
struct T_range_filters const*const range_filters) \
{ \
return \
(!use_amount_of_money || \
(row->amount_of_money >= range_filters->begin.amount_of_money && \
row->amount_of_money <= range_filters->end.amount_of_money)) && \
(!use_gender || \
(row->gender >= range_filters->begin.gender && \
row->gender <= range_filters->end.gender)) && \
(!use_age || \
(row->age >= range_filters->begin.age && \
row->age <= range_filters->end.age)); \
}
#define DECL2(m, g) DECLARE(m, g, 0) DECLARE(m, g, 1)
#define DECL1(m) DECL2(m, 0) DECL2(m, 1)
DECL1(0)
DECL1(1)
Содержательность сообщений компилятора при ошибках в макросах на порядок ниже, чем при ошибках в шаблонах
note: candidates are: typename std::vector<_Tp, _Alloc>::iteratorПрямо написано, что передавать надо итератор, а не значение.
// Get pointers to the constant `1'.
Value *One = ConstantInt::get(Type::getInt32Ty(Context), 1);
// Get pointers to the integer argument of the add1 function...
assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg
Argument *ArgX = Add1F->arg_begin(); // Get the arg
ArgX->setName("AnArg"); // Give it a nice symbolic name for fun.
// Create the add instruction, inserting it into the end of BB.
Instruction *Add = BinaryOperator::CreateAdd(One, ArgX, "addresult", BB);
// Create the return instruction and add it to the basic block
ReturnInst::Create(Context, Add, BB);
fprintf(fout, "return x + 1;");. Вдобавок такой способ портируем на любую ОС, в которой есть компилятор си, который может создавать разделяемые библиотеки.int main(void){
eval("printf(\"Hello, world!\\n\")");
return 0;
}
c_array_size, равный use_filter), но и сами граничные значения (begin и end). В вашем же решении на шаблонах генерируются шаблоны для каждого варианта use_filter, но begin и end по-прежнему остаются runtime-переменными. Естественно, то же самое получилось бы и при использовании LLVM (в смысле LLVM имел бы такую же скорость, как и мой псевдо-JIT).begin и end, я написал специальный вариант моего кода, в котором begin и end являются переменными времени исполнения. Вот он: paste.org.ru/?q7gu4p. Как и следовало ожидать, время выполнения получилось такое же, как и у решения на шаблонах: 0.88 секунд.Неоптимизированный поиск на C | 1.41, 1.34, 1.47 (было 3 теста) Шаблоны C++ | 0.88 Псевдо-JIT | 0.54 (+0.02 на саму "компиляцию на лету") Псевдо-JIT с переменными begin и end | 0.88 (+0.02 на "компиляцию")
test_predicate, потом в рантайме выбрать нужный из этих вариантов, а потом записать прямо в (уже скомпилированный) машинный код значения begin и end и передать управление этому модифицированному коду. (Если непонятно, могу подробнее объяснить.)begin и end будут с точки зрения самой функции test_predicate константами. Но при этом не надо делать JIT. Достаточно лишь поменять машинный код во время исполнения, а это занимает лишь единицы тактов процессора, в отличие от JIT.Как мне кажется, в случае константных begin и end компилятор оптимизирует код под эти константы, и просто так заменить их в получившемся машинном коде не получится.
Возможности оптимизации в языках C и C++