В программе обрабатываются сущности (назовём их элементами).
С каждым элементом связан массив аттрибутов.
Каждый аттрибут задаётся структурой:
enum attr_e {/**/};
struct attr_data
{
attr_e code; // код аттрибута
iterator_range data; // пара итераторов, указывающих откуда можно считать значение аттрибута
};
Количество аттрибутов во много раз превышает количество элементов.(аттрибутов ~= 300, элементов ~= 25)
Типы аттрибутов подразделяются на группы
У различных элементов есть одинаковые типы аттрибутов.
То есть общая картина получается такой:
void proceed_element(const element_data& el)
{
switch (el.code)
{
case elem_1:
proceed_element_1(el.attr, el.num_attr);
break;
case elem_2:
proceed_element_2(el.attr, el.num_attr);
break;
};
}
//---------------------------------------------void proceed_element_1(const attr_data* attr, unsigned num_attr)
{
set_group1_attributes(attr, num_attr);
set_group2_attributes(attr, num_attr);
set_group3_attributes(attr, num_attr);
// обработка индивидуальных аттрибутов для этого элемента
//...
}
//---------------------------------------------void proceed_element_1(const attr_data* attr, unsigned num_attr)
{
set_group1_attributes(attr, num_attr);
set_group3_attributes(attr, num_attr);
// обработка индивидуальных аттрибутов для этого элемента
//...
}
//---------------------------------------------void set_group1_attributes(const attr_data * attr, unsigned num_attr)
{
for (unsigned i(0); i < num_attr; ++i)
{
switch (attr[i].code)
{
// обработка аттрибутов из своей группы
}
}
}
все функции set_groupX_attributes(...) реализованы одинаковым образом, то есть цикл по массиву аттрибутов, в теле цикла обрабатываются аттрибуты из своей группы.
Уффф... вроде всё... Итак, мне не нравится то что мне приходится по несколько раз проходится по всем элементам одного и того же массива.
И даже если я уже обработал аттрибут, его код всё равно будет проверяться в других функциях.
Что мне пришло на ум:
я добавляю два дополнительных члена к структуре attr_data
struct attr_data
{
unsigned char next;
unsigned char prev; //(255 элементов в списке будет достаточно)
attr_e code; // код аттрибута
iterator_range data; // пара итераторов, указывающих откуда можно считать значение аттрибута
};
и с помощью них организую простой двухсвязный список. Потом, если аттрибут обработан, я удаляю его из списка (удаление сводится к корректировке членов next, prev)
Больше мне ничего уже не придумывается.
Собственно вопрос в том, что может кто то подскажет что то лучше.
Спасибо если дочитали до конца.
Re: Как бы лучше сделать (лучше название не придумал :)
Здравствуйте, korzhik, Вы писали:
K>и с помощью них организую простой двухсвязный список. Потом, если аттрибут обработан, я удаляю его из списка (удаление сводится к корректировке членов next, prev) K>Больше мне ничего уже не придумывается. K>Собственно вопрос в том, что может кто то подскажет что то лучше.
А язык какой?
С++ — наследование + visitor
C — танцы с бубном (эмуляция наследования и визитора)
Re[2]: Как бы лучше сделать (лучше название не придумал :)
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Здравствуйте, korzhik, Вы писали:
K>>и с помощью них организую простой двухсвязный список. Потом, если аттрибут обработан, я удаляю его из списка (удаление сводится к корректировке членов next, prev) K>>Больше мне ничего уже не придумывается. K>>Собственно вопрос в том, что может кто то подскажет что то лучше. PC>А язык какой?
язык С++
PC>С++ — наследование + visitor
Ээээ... можешь привести пример, если тебе не сложно ... я чего то недогоняю куда их сюда сувать
Re: Как бы лучше сделать (лучше название не придумал :)
Здравствуйте, korzhik, Вы писали:
K>Здравствуйте,
K>В программе обрабатываются сущности (назовём их элементами). K>С каждым элементом связан массив аттрибутов. K> ...
Стиль в лучших традициях С
Почему бы не применить объекты, наследование, функции-члены и т.д. Зачем нужны enum'ы, на которых происходят switch'и?
Здравствуйте, remark, Вы писали:
R>Здравствуйте, korzhik, Вы писали:
K>>Здравствуйте,
K>>В программе обрабатываются сущности (назовём их элементами). K>>С каждым элементом связан массив аттрибутов. K>> ...
R>Стиль в лучших традициях С R>Почему бы не применить объекты, наследование, функции-члены и т.д. Зачем нужны enum'ы, на которых происходят switch'и?
R>Можно как-то так (если я правильно понял смысл):
Здравствуйте, remark, Вы писали:
R>Здравствуйте, korzhik, Вы писали:
K>>Здравствуйте,
K>>В программе обрабатываются сущности (назовём их элементами). K>>С каждым элементом связан массив аттрибутов. K>> ...
R>Стиль в лучших традициях С
Это да...
Зато летает, ты даже не можешь представить как
R>Можно как-то так (если я правильно понял смысл):
[ccode] R>struct attr_data R>{ R> iterator_range data; // пара итераторов, указывающих откуда можно считать значение аттрибута R> virtual void set_group_attributes() = 0; R>};
R>struct attr_data1 : attr_data R>{ R> virtual void set_group_attributes() R> { R> ... R> } R>}; R>struct attr_data2 : attr_data R>{ R> virtual void set_group_attributes() R> { R> ... R> } R>};
[/сcode]
у меня 300 типов аттрибутов, на каждый класс заводить?
R>И т.д.. Можно так же применить std::vector и т.д. R>
Удачный смайлик... я как раз сейчас лечу бессоницу пивом
ЗЫ
В общем решил пока сделать без списков, банально с флажком "обработано/не обработано". Всё равно среднее количество аттрибутов на элемент штук 5-8 не больше.
Re: Как бы лучше сделать (лучше название не придумал :)
Здравствуйте, korzhik, Вы писали:
K>Здравствуйте,
K>В программе обрабатываются сущности (назовём их элементами). K>С каждым элементом связан массив аттрибутов. K>[...] K>Собственно вопрос в том, что может кто то подскажет что то лучше.
K>Спасибо если дочитали до конца.
Есть предложение. Смысл в том, что по списку атрибутов пробегаться только 1 раз, а каждый атрибут обрабатывать (посещать, visit — как писали другие) в соответствии с его типом. Если сейчас у тебя тип атрибута выражен числовой константой, то это switch-case в простейшем варианте. Но эффективнее для каждого типа атрибута завести свой класс и воспользоваться виртуальными функциями. Т.е. у каждого класса атрибута будет своя виртуальная функция обработки.
Как развитие этой темы можно на этом механизме реализовать полноценное посещение — когда указанная виртуальная функция класса атрибута будет только вызывать другую функцию у внешнего объекта-посетителя (visitor). Тут может помочь перегрузка. Если все еще не понятно, можно что-нибудь набросать (сейчас спать хоцца).
Re: Как бы лучше сделать (лучше название не придумал :)
От:
Аноним
Дата:
27.07.05 06:51
Оценка:
Здравствуйте, korzhik, Вы писали:
K>Спасибо если дочитали до конца.
Не понятно, конечно. Но то что группы аттрибутов определяются switch'ем, а не структурами данных, кажется подозрительным.
Re: Как бы лучше сделать (лучше название не придумал :)
Здравствуйте, lastique, Вы писали:
L>Есть предложение. Смысл в том, что по списку атрибутов пробегаться только 1 раз, а каждый атрибут обрабатывать (посещать, visit — как писали другие) в соответствии с его типом. Если сейчас у тебя тип атрибута выражен числовой константой, то это switch-case в простейшем варианте. Но эффективнее для каждого типа атрибута завести свой класс и воспользоваться виртуальными функциями. Т.е. у каждого класса атрибута будет своя виртуальная функция обработки.
у меня 300 типов аттрибутов. Как я понял ты предлагаешь на каждый тип заводить отдельный класс. Я не готов на такие подвиги пока
L>Как развитие этой темы можно на этом механизме реализовать полноценное посещение — когда указанная виртуальная функция класса атрибута будет только вызывать другую функцию у внешнего объекта-посетителя (visitor). Тут может помочь перегрузка. Если все еще не понятно, можно что-нибудь набросать (сейчас спать хоцца).
Да не надо, спасибо Я знаю паттерн visitor.
Re[2]: Как бы лучше сделать (лучше название не придумал :)
Здравствуйте, sadomovalex, Вы писали:
S>Здравствуйте, korzhik, Вы писали:
K>>Спасибо если дочитали до конца.
S>подобную задачу я в свое времяч решил с помощью двойной адресации. Расскажу на примере вектора (new/delete лень набирать):
Спасибо за твой ответ. Идею я понял. Ну чтож... это тоже вариант.
Пока всё таки решил сделать вариант с флажками, ну а потом если чего, можно будет и твой вариант попробовать
Re: Как бы лучше сделать (лучше название не придумал :)
Можно попробовать в начале функции proceed_element_X создавать новый контейнер с атрибутами (ну или с указателями на объекты-атрибуты), и передавать его в функции set_groupX_attributes. А эти функции будут выбрасывать обработанные элементы:
void proceed_element_1(const attr_data* attr, unsigned num_attr)
{
std::vector<attr_data> v(attr, attr+num_attr);
set_group1_attributes(v);
set_group2_attributes(v);
set_group3_attributes(v);
// обработка индивидуальных аттрибутов для этого элемента (работаем с v)
//...
}
...
void set_group1_attributes(std::vector<attr_data>& attr)
{
for (unsigned i(0); i < num_attr; ++i)
{
switch (attr[i].code)
{
// обработка аттрибутов из своей группы и последующее удаление из v// корректный проход с удалением писать лень :-)
}
}
}
Любите книгу — источник знаний (с) М.Горький
Re[3]: Как бы лучше сделать (лучше название не придумал :)
Здравствуйте, korzhik, Вы писали:
K>Здравствуйте, remark, Вы писали:
R>>Здравствуйте, korzhik, Вы писали:
K>>>Здравствуйте,
K>>>В программе обрабатываются сущности (назовём их элементами). K>>>С каждым элементом связан массив аттрибутов. K>>> ...
R>>Стиль в лучших традициях С K>Это да... K>Зато летает, ты даже не можешь представить как
На С++ будет летать не хуже. С++ сам по себе не имеет ничего, что ухудшало бы его скорось по сравнению с С. На нём даже легче писать более оптимальный код imho.
K>у меня 300 типов аттрибутов, на каждый класс заводить?
Ну ты же заводишь на каждый аттрибут функцию обработки???
R>>И т.д.. Можно так же применить std::vector и т.д. R>> K>Удачный смайлик... я как раз сейчас лечу бессоницу пивом
K>ЗЫ K>В общем решил пока сделать без списков, банально с флажком "обработано/не обработано". Всё равно среднее количество аттрибутов на элемент штук 5-8 не больше.
Дело, конечно, вкуса и стиля и зависит от проекта...
Ну тогда ты можешь не перебирать много раз все аттрибуты, а один раз перебрать все аттрибуты и сразу для каждого находить функцию, которая должна его обрабатывать, и обрабатывать его ей ... что в общем-то и есть виртальные функции. В предложенном варианте это просто будет быстрее, т.к. с каждым аттрибутом автоматически храниться указатель на функцию, которая должна его обрабатывать (что в общем то тоже можно реализовать вручную).
Здравствуйте, remark, Вы писали:
R>Ну тогда ты можешь не перебирать много раз все аттрибуты, а один раз перебрать все аттрибуты и сразу для каждого находить функцию, которая должна его обрабатывать, и обрабатывать его ей ... что в общем-то и есть виртальные функции. В предложенном варианте это просто будет быстрее, т.к. с каждым аттрибутом автоматически храниться указатель на функцию, которая должна его обрабатывать (что в общем то тоже можно реализовать вручную). R>
Если это объекты и аттрибуты чаще используются, чем создаются, то можно действительно в атрибутах помимо типа хранить указатель на функцию, которая должна его обрабатывать.
При обработке перебирать массив один раз и вызвать для каждого атрибута функцию, которая храниться с ним же.
Здравствуйте, remark, Вы писали:
K>>у меня 300 типов аттрибутов, на каждый класс заводить?
R>Ну ты же заводишь на каждый аттрибут функцию обработки???
нет
K>>ЗЫ K>>В общем решил пока сделать без списков, банально с флажком "обработано/не обработано". Всё равно среднее количество аттрибутов на элемент штук 5-8 не больше.
R>Дело, конечно, вкуса и стиля и зависит от проекта...
нет, тут дело практики, как будет лучше, так и сделаю.
R>Ну тогда ты можешь не перебирать много раз все аттрибуты, а один раз перебрать все аттрибуты и сразу для каждого находить функцию, которая должна его обрабатывать, и обрабатывать его ей ... что в общем-то и есть виртальные функции. В предложенном варианте это просто будет быстрее, т.к. с каждым аттрибутом автоматически храниться указатель на функцию, которая должна его обрабатывать (что в общем то тоже можно реализовать вручную).
На каждый аттрибут делать функцию, и делать массив ук-ей на функции... была такая мысль у меня, но пока руки не доходят.