Как бы лучше сделать (лучше название не придумал :)
От: korzhik Россия  
Дата: 26.07.05 15:31
Оценка:
Здравствуйте,

В программе обрабатываются сущности (назовём их элементами).
С каждым элементом связан массив аттрибутов.
Каждый аттрибут задаётся структурой:
enum attr_e {/**/};

struct attr_data
{
  attr_e         code; // код аттрибута
  iterator_range data; // пара итераторов, указывающих откуда можно считать значение аттрибута
};


В итоге имеем метод обработки элемента:
enum element_e {/**/};

struct element_data
{
  element_e code;
  const attr_data* attr;
  unsigned num_attr;  
};

void proceed_element(const element_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: Как бы лучше сделать (лучше название не придумал :)
От: Pavel Chikulaev Россия  
Дата: 26.07.05 17:47
Оценка:
Здравствуйте, korzhik, Вы писали:

K>и с помощью них организую простой двухсвязный список. Потом, если аттрибут обработан, я удаляю его из списка (удаление сводится к корректировке членов next, prev)

K>Больше мне ничего уже не придумывается.
K>Собственно вопрос в том, что может кто то подскажет что то лучше.
А язык какой?

С++ — наследование + visitor
C — танцы с бубном (эмуляция наследования и визитора)
Re[2]: Как бы лучше сделать (лучше название не придумал :)
От: korzhik Россия  
Дата: 26.07.05 18:03
Оценка:
Здравствуйте, Pavel Chikulaev, Вы писали:

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


K>>и с помощью них организую простой двухсвязный список. Потом, если аттрибут обработан, я удаляю его из списка (удаление сводится к корректировке членов next, prev)

K>>Больше мне ничего уже не придумывается.
K>>Собственно вопрос в том, что может кто то подскажет что то лучше.
PC>А язык какой?

язык С++

PC>С++ — наследование + visitor


Ээээ... можешь привести пример, если тебе не сложно ... я чего то недогоняю куда их сюда сувать
Re: Как бы лучше сделать (лучше название не придумал :)
От: remark Россия http://www.1024cores.net/
Дата: 26.07.05 19:59
Оценка:
Здравствуйте, korzhik, Вы писали:

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


K>В программе обрабатываются сущности (назовём их элементами).

K>С каждым элементом связан массив аттрибутов.
K> ...

Стиль в лучших традициях С
Почему бы не применить объекты, наследование, функции-члены и т.д. Зачем нужны enum'ы, на которых происходят switch'и?

Можно как-то так (если я правильно понял смысл):


struct attr_data
{
  iterator_range data; // пара итераторов, указывающих откуда можно считать значение аттрибута
  virtual void set_group_attributes() = 0;
};

struct attr_data1 : attr_data
{
  virtual void set_group_attributes()
  {
  ...
  }
};

struct attr_data2 : attr_data
{
  virtual void set_group_attributes()
  {
  ...
  }
};

struct element_data
{
  const attr_data* attr;
  unsigned num_attr;  
  virtual void proceed_element() = 0
  {
     for (int i = 0; i < num_attr; ++i)
    {
       num_attr[i].set_group_attributes();
    }
};

struct element_data1 : element_data
{
  virtual void proceed_element()
  {
    element_data::proceed_element();
  ...
  }
};

struct element_data2 : element_data
{
  virtual void proceed_element()
  {
    element_data::proceed_element();
  ...
  }
};



И т.д.. Можно так же применить std::vector и т.д.

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Как бы лучше сделать (лучше название не придумал :)
От: remark Россия http://www.1024cores.net/
Дата: 26.07.05 20:06
Оценка:
Здравствуйте, remark, Вы писали:

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


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


K>>В программе обрабатываются сущности (назовём их элементами).

K>>С каждым элементом связан массив аттрибутов.
K>> ...

R>Стиль в лучших традициях С

R>Почему бы не применить объекты, наследование, функции-члены и т.д. Зачем нужны enum'ы, на которых происходят switch'и?

R>Можно как-то так (если я правильно понял смысл):



R>
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>};

R>struct element_data
R>{
R>  const attr_data* attr;
R>  unsigned num_attr;  
R>  virtual void proceed_element() = 0
R>  {
R>     for (int i = 0; i < num_attr; ++i)
R>    {
R>       num_attr[i].set_group_attributes();
R>    }
R>};

R>struct element_data1 : element_data
R>{
R>  virtual void proceed_element()
R>  {
R>    element_data::proceed_element();
R>  ...
R>  }
R>};

R>struct element_data2 : element_data
R>{
R>  virtual void proceed_element()
R>  {
R>    element_data::proceed_element();
R>  ...
R>  }
R>};
R>



R>И т.д.. Можно так же применить std::vector и т.д.

R>

Сюда уже можно прикрутить и visitor

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Как бы лучше сделать (лучше название не придумал :)
От: korzhik Россия  
Дата: 26.07.05 20:53
Оценка:
Здравствуйте, 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: Как бы лучше сделать (лучше название не придумал :)
От: lastique  
Дата: 26.07.05 23:54
Оценка:
Здравствуйте, korzhik, Вы писали:

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


K>В программе обрабатываются сущности (назовём их элементами).

K>С каждым элементом связан массив аттрибутов.
K>[...]
K>Собственно вопрос в том, что может кто то подскажет что то лучше.

K>Спасибо если дочитали до конца.


Есть предложение. Смысл в том, что по списку атрибутов пробегаться только 1 раз, а каждый атрибут обрабатывать (посещать, visit — как писали другие) в соответствии с его типом. Если сейчас у тебя тип атрибута выражен числовой константой, то это switch-case в простейшем варианте. Но эффективнее для каждого типа атрибута завести свой класс и воспользоваться виртуальными функциями. Т.е. у каждого класса атрибута будет своя виртуальная функция обработки.

Как развитие этой темы можно на этом механизме реализовать полноценное посещение — когда указанная виртуальная функция класса атрибута будет только вызывать другую функцию у внешнего объекта-посетителя (visitor). Тут может помочь перегрузка. Если все еще не понятно, можно что-нибудь набросать (сейчас спать хоцца).
Re: Как бы лучше сделать (лучше название не придумал :)
От: Аноним  
Дата: 27.07.05 06:51
Оценка:
Здравствуйте, korzhik, Вы писали:

K>Спасибо если дочитали до конца.


Не понятно, конечно. Но то что группы аттрибутов определяются switch'ем, а не структурами данных, кажется подозрительным.
Re: Как бы лучше сделать (лучше название не придумал :)
От: sadomovalex Россия http://sadomovalex.blogspot.com
Дата: 27.07.05 08:11
Оценка: 8 (1)
Здравствуйте, korzhik, Вы писали:

K>Спасибо если дочитали до конца.


подобную задачу я в свое времяч решил с помощью двойной адресации. Расскажу на примере вектора (new/delete лень набирать):
enum attr_e { attr_1, attr_2, attr_3 };
struct attr_data
{
  attr_e         code;
  iterator_range data;
};

enum element_e {elem_1, elem_2};
struct element_data
{
  element_e code;
  attr_data* attr;
  unsigned num_attr;  
};

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)
{

  // заполняем массив необработанными индексами
  vector<int> idx;
  idx.reserve(num_attr);
  for (int i = 0; i < num_attr; ++i)
      idx.push_back(i);

  set_group1_attributes(attr, idx);
  set_group2_attributes(attr, idx);
}
// в 1-ю группу входят аттрибуты с кодом attr_1 и attr_2
void set_group1_attributes(const attr_data * attr, vector<int>& idx)
{
  vector<int>::size_type i = 0;
  while(i < idx.size())
  {
    switch (attr[idx[i]].code)
    {
    case attr_1:
        cout << "1\n";
        idx.erase(idx.begin() + i);
        continue;
    case attr_2:
        cout << "2\n";
        idx.erase(idx.begin() + i);
        continue;
    }

    ++i;
  }
}
// во 2-ю группу входят аттрибуты с кодом attr_3
void set_group2_attributes(const attr_data * attr, vector<int>& idx)
{
  vector<int>::size_type i = 0;
  while(i < idx.size())
  {
    switch (attr[idx[i]].code)
    {
    case attr_3:
        cout << "3\n";
        idx.erase(idx.begin() + i);
        continue;
    }

    ++i;
  }
}

в результате в соответствующей процедуре мы обрабатываем только нужные элементы
"Что не завершено, не сделано вовсе" Гаусс
Re[2]: Как бы лучше сделать (лучше название не придумал :)
От: korzhik Россия  
Дата: 27.07.05 08:17
Оценка:
Здравствуйте, lastique, Вы писали:

L>Есть предложение. Смысл в том, что по списку атрибутов пробегаться только 1 раз, а каждый атрибут обрабатывать (посещать, visit — как писали другие) в соответствии с его типом. Если сейчас у тебя тип атрибута выражен числовой константой, то это switch-case в простейшем варианте. Но эффективнее для каждого типа атрибута завести свой класс и воспользоваться виртуальными функциями. Т.е. у каждого класса атрибута будет своя виртуальная функция обработки.

у меня 300 типов аттрибутов. Как я понял ты предлагаешь на каждый тип заводить отдельный класс. Я не готов на такие подвиги пока

L>Как развитие этой темы можно на этом механизме реализовать полноценное посещение — когда указанная виртуальная функция класса атрибута будет только вызывать другую функцию у внешнего объекта-посетителя (visitor). Тут может помочь перегрузка. Если все еще не понятно, можно что-нибудь набросать (сейчас спать хоцца).

Да не надо, спасибо Я знаю паттерн visitor.
Re[2]: Как бы лучше сделать (лучше название не придумал :)
От: korzhik Россия  
Дата: 27.07.05 08:41
Оценка:
Здравствуйте, sadomovalex, Вы писали:

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


K>>Спасибо если дочитали до конца.


S>подобную задачу я в свое времяч решил с помощью двойной адресации. Расскажу на примере вектора (new/delete лень набирать):


Спасибо за твой ответ. Идею я понял. Ну чтож... это тоже вариант.
Пока всё таки решил сделать вариант с флажками, ну а потом если чего, можно будет и твой вариант попробовать
Re: Как бы лучше сделать (лучше название не придумал :)
От: Bell Россия  
Дата: 27.07.05 09:33
Оценка:
Здравствуйте, korzhik, Вы писали:


Можно попробовать в начале функции 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]: Как бы лучше сделать (лучше название не придумал :)
От: remark Россия http://www.1024cores.net/
Дата: 27.07.05 21:16
Оценка:
Здравствуйте, korzhik, Вы писали:

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


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


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


K>>>В программе обрабатываются сущности (назовём их элементами).

K>>>С каждым элементом связан массив аттрибутов.
K>>> ...

R>>Стиль в лучших традициях С

K>Это да...
K>Зато летает, ты даже не можешь представить как

На С++ будет летать не хуже. С++ сам по себе не имеет ничего, что ухудшало бы его скорось по сравнению с С. На нём даже легче писать более оптимальный код imho.

K>у меня 300 типов аттрибутов, на каждый класс заводить?


Ну ты же заводишь на каждый аттрибут функцию обработки???

R>>И т.д.. Можно так же применить std::vector и т.д.

R>>
K>Удачный смайлик... я как раз сейчас лечу бессоницу пивом


K>ЗЫ

K>В общем решил пока сделать без списков, банально с флажком "обработано/не обработано". Всё равно среднее количество аттрибутов на элемент штук 5-8 не больше.

Дело, конечно, вкуса и стиля и зависит от проекта...

Ну тогда ты можешь не перебирать много раз все аттрибуты, а один раз перебрать все аттрибуты и сразу для каждого находить функцию, которая должна его обрабатывать, и обрабатывать его ей ... что в общем-то и есть виртальные функции. В предложенном варианте это просто будет быстрее, т.к. с каждым аттрибутом автоматически храниться указатель на функцию, которая должна его обрабатывать (что в общем то тоже можно реализовать вручную).

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Как бы лучше сделать (лучше название не придумал :)
От: remark Россия http://www.1024cores.net/
Дата: 27.07.05 22:23
Оценка: 1 (1)
Здравствуйте, remark, Вы писали:

R>Ну тогда ты можешь не перебирать много раз все аттрибуты, а один раз перебрать все аттрибуты и сразу для каждого находить функцию, которая должна его обрабатывать, и обрабатывать его ей ... что в общем-то и есть виртальные функции. В предложенном варианте это просто будет быстрее, т.к. с каждым аттрибутом автоматически храниться указатель на функцию, которая должна его обрабатывать (что в общем то тоже можно реализовать вручную).

R>


Если это объекты и аттрибуты чаще используются, чем создаются, то можно действительно в атрибутах помимо типа хранить указатель на функцию, которая должна его обрабатывать.
При обработке перебирать массив один раз и вызвать для каждого атрибута функцию, которая храниться с ним же.

Очень быстро

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Как бы лучше сделать (лучше название не придумал :)
От: korzhik Россия  
Дата: 28.07.05 08:42
Оценка:
Здравствуйте, remark, Вы писали:

K>>у меня 300 типов аттрибутов, на каждый класс заводить?


R>Ну ты же заводишь на каждый аттрибут функцию обработки???


нет

K>>ЗЫ

K>>В общем решил пока сделать без списков, банально с флажком "обработано/не обработано". Всё равно среднее количество аттрибутов на элемент штук 5-8 не больше.

R>Дело, конечно, вкуса и стиля и зависит от проекта...

нет, тут дело практики, как будет лучше, так и сделаю.

R>Ну тогда ты можешь не перебирать много раз все аттрибуты, а один раз перебрать все аттрибуты и сразу для каждого находить функцию, которая должна его обрабатывать, и обрабатывать его ей ... что в общем-то и есть виртальные функции. В предложенном варианте это просто будет быстрее, т.к. с каждым аттрибутом автоматически храниться указатель на функцию, которая должна его обрабатывать (что в общем то тоже можно реализовать вручную).


На каждый аттрибут делать функцию, и делать массив ук-ей на функции... была такая мысль у меня, но пока руки не доходят.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.