Russian Qt Forum

Программирование => Общий => Тема начата: Igors от Август 26, 2015, 12:13



Название: Запись "изменений"
Отправлено: Igors от Август 26, 2015, 12:13
Добрый день

В задаче "запись данных анимации" (недавно обсуждалось) удалось обойтись без этого,  но необходимость возникла в смежной задаче.

Есть (большая) структура в памяти. В какой-то момент приходит ключ (или неск ключей). Если значение ключа ненулевое, то нужно сделать копию текущей структуры и в ней изменить значение полей по этому ключу. Псевдокод
Код
C++ (Qt)
struct CData {
float mAmount;  
int  mSomeVal;
// .. еще 100 таких
};  
 
void SetupData( const CData & src, CData & dst, int key )
{
dst = src;  // копируем
dst.mAmount = ???  // какие-то поля меняем
}
Нужно как-то идентифицировать какое поле менять и знать на что менять. В момент записи это известно, т.е. мы знаем что mAmount должно меняться, и мы имеем контейнер подставляемых значений из которых по ключу будет выбрано нужное.

Как должна выглядеть реализация с точки зрения читающего (подставляющего)?

Спасибо


Название: Re: Запись "изменений"
Отправлено: m_ax от Август 26, 2015, 14:09
Цитировать
Как должна выглядеть реализация с точки зрения читающего (подставляющего)?

Например так:

Код
C++ (Qt)
struct CData
{
   float mAmount;
   int  mSomeVal;
};
 
 
enum keys
{
   key0,
   key1
};
 
 
class setter
{
public:
   typedef boost::variant<int, float> variant_t;
   typedef int key_t;
   typedef std::map<key_t, std::function<void (setter*, const variant_t &)>> map_t;
 
   setter(CData & data) : m_data(data)
   {
       m_map[keys::key0] = std::function<void (setter*,  const variant_t &)>(&setter::set_amount);
       m_map[keys::key1] = std::function<void (setter*,  const variant_t &)>(&setter::set_some_val);
   }
 
   template <class T>
   void set(key_t key, const T & val, const CData & src)
   {
       m_data = src;
       m_map[key](this, val);
   }
 
private:
   CData & m_data;
   map_t m_map;
 
   void set_amount(const variant_t & val) { m_data.mAmount = boost::get<decltype(m_data.mAmount)>(val); }
   void set_some_val(const variant_t & val) { m_data.mSomeVal = boost::get<decltype(m_data.mSomeVal)>(val); }
};
 
 
 
int main()
{
 
   CData dst;
   CData src;
 
   setter mysetter(dst);
 
   mysetter.set(keys::key0, 12.9f, src);
 
   std::cout << dst.mAmount << std::endl;
 
   mysetter.set(keys::key1, 100500, src);
 
   std::cout << dst.mSomeVal << std::endl;
 
 
 
   return 0;
}
 


Название: Re: Запись "изменений"
Отправлено: Igors от Август 27, 2015, 11:29
Пример, см аттач. Есть 3 кубика которые представлены как одна модель и используют один зкземпляр CData. Пусть mAmount - прозрачность текстуры которая должна быть разной для разных кубиков. Ясно что мы должны как-то отличать кубики друг от друга. Заметим что они могут рендеоиться в любом порядке, напр сначала точка 2-го (нужна одна прозрачность), потом точка первого (другая), потом опять второго. Поэтому вписываем ключи  - (уникальные ID). В полигоны 1-го запишем 1, второго 2  и.т.д. Эта операция делается 1 раз на старте

Теперь нам надо превратить ID ключа в конкретные значения изменяемых параметров. Для этого в объекте есть такие данные

1) Что менять. Идентифицируется строкой (напр "Amount") один раз на старте. То есть mAmount меняется или всегда или никогда.

2) Массив данных для изменения, индивидуальный для каждого меняемого параметра. Загружается на старте и никогда не меняется. Напр там записано 2 значения 0.0f и 1.0f. Или 3 (1, 0,5, 0, 1)

3) Как менять, это число - номер метода или "способ замены". Напр число 1 значит "выбросить случайное число" (конечно используя ключ ID) и по нему выбрать значение из массива данных, возможно интерполируя

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


Название: Re: Запись "изменений"
Отправлено: m_ax от Август 28, 2015, 14:31
Цитировать
Теперь нам надо превратить ID ключа в конкретные значения изменяемых параметров.

Тогда напрашивается написать свой класс ключа, который знает что и как менять в том объекте к которому он приставлен..
Это уже даже и не ключ, а скорее набор харрактеристик и действий..

 


Название: Re: Запись "изменений"
Отправлено: Igors от Август 30, 2015, 10:23
Тогда напрашивается написать свой класс ключа, который знает что и как менять в том объекте к которому он приставлен..
Это уже даже и не ключ, а скорее набор харрактеристик и действий..
Для примера выше: ключ - идентификатор кубика (одного из многих), это просто число, без всякого интеллекта. Класс (выполняющий изменения) конечно есть, и конечно ключ он получает как аргумент. На основании этого ключа он вычислит "измененное значение", но нужен общий механизм куда это значение поместить (т.е. собственно поменять)


Название: Re: Запись "изменений"
Отправлено: Old от Август 30, 2015, 12:42
m_ax говорит о чем-то типа этого:
Код
C++ (Qt)
class Mutabler
{
   ....
private:
   Key    m_key;    // Тот самый ключ
   map<string, variant>    m_values;    // Коллекция с измененными значениями (название параметра : значение )
};
 
У нас есть ключ и значения которые нужно изменить у этплонного объекта.


Название: Re: Запись "изменений"
Отправлено: m_ax от Август 30, 2015, 12:55
Цитировать
m_ax говорит о чем-то типа этого:

Да, именно так  :)


Название: Re: Запись "изменений"
Отправлено: Igors от Август 30, 2015, 13:58
Да, именно так  :)
Не так :) Ключ - для генерации измененного значения, это не селектор изменяемого поля. С полем сделал так
Цитировать
{ "Amount", offsetof(struct MyClass, mAmount) },
{ "SomeVal", offsetof(struct MyClass, mSomeVal) }
... еще 100 таких
Жесткая макруха (Саня Грей ???) - но лучшего не видно