Информация об изменениях

Сообщение Re: Метод класс как С колбек от 09.04.2015 9:51

Изменено 09.04.2015 9:55 uzhas

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

AHO>Имеется С библиотека с неизменяемым интерфейсом, одна из функций выглядит так:

AHO>internalState – сугубо внутренняя структура библиотеки, data – данные получаемые из библиотеки, т.е. никаких void * userData нет.

обычно в C библиотеках дают возможность просунуть void* userData, поищите внимательнее, либо сообщите название библиотеки, чтобы мы убедились

AHO>Не могу понять, возможно ли здесь воспользоваться лямбдой или bind(оба параметра: internalState, data — должны быть доступны):


по задумке нельзя

AHO>В чём загвоздка?


на самом деле ваша проблема довольно распространена и существует несколько подходов для ее решения
1) заводим глобальную переменную, кладем туда this, пишем глобальную функцию, которая имеет сигнатуру Callback и которая при вызове сделает перевызов thisObject->CallbackMethod()
2) глобальную переменную еще можно держать в TLS
3) зоопарк переменных можно зашаблонить
typedef void(*ExtendedCallback)(void * internalState, Data * data, void* userData);

template <typename tag>
struct CallbackHolder
{
  static void Func(void * internalState, Data * data)
  {
    UserCallback(internalState, data, UserData);
  }

  static void* UserData = nullptr;
  static ExtendedCallback UserCallback = nullptr;
}

//usage
struct MyTag1 {} ;// create any number of tags
//probably, we need to define static data
void* CallbackHolder<MyTag1>::UserData = nullptr;
ExtendedCallback CallbackHolder<MyTag1>::UserCallback = nullptr;

Callback<MyTag1> c; // track lifetime as needed
Callback fn = &Callback<MyTag1>::Func;
addCallback(state, fn);


4) заморачиваемся с динамическими колбеками-трамплинами. их можно поддерживать динамически или сразу выделить пул из 100 колбеков. рекомендую гуглить по словам trampoline, thunk
суть thunk в том, что он содержит секцию для хранения void* (доп данных) + расширенный колбек и содержит ассемблерный код, который перевызывает расширенный кол-бек со всеми данными
метакод
typedef void(*ExtendedCallback)(void * internalState, Data * data, void* userData);

struct ThunkData
{
  <executable code>
  void* UserData;
  ExtendedCallback UserCallback;
};

ThunkData* data = ...; <- get from pool or allocate somehow
data->UserData = myData;
data->UserCallback = mySuperCallback;
Callback fn = (Callback)(&data); <--- pointer to executable code inside thunk
addCallback(state, fn);


успехов
Здравствуйте, AHOHUM, Вы писали:

AHO>Имеется С библиотека с неизменяемым интерфейсом, одна из функций выглядит так:

AHO>internalState – сугубо внутренняя структура библиотеки, data – данные получаемые из библиотеки, т.е. никаких void * userData нет.

обычно в C библиотеках дают возможность просунуть void* userData, поищите внимательнее, либо сообщите название библиотеки, чтобы мы убедились

AHO>Не могу понять, возможно ли здесь воспользоваться лямбдой или bind(оба параметра: internalState, data — должны быть доступны):


по задумке нельзя

AHO>В чём загвоздка?


на самом деле ваша проблема довольно распространена и существует несколько подходов для ее решения
1) заводим глобальную переменную, кладем туда this, пишем глобальную функцию, которая имеет сигнатуру Callback и которая при вызове сделает перевызов thisObject->CallbackMethod()
2) глобальную переменную еще можно держать в TLS
3) зоопарк переменных можно зашаблонить
typedef void(*ExtendedCallback)(void * internalState, Data * data, void* userData);

template <typename tag>
struct CallbackHolder
{
  static void Func(void * internalState, Data * data)
  {
    UserCallback(internalState, data, UserData);
  }

  static void* UserData = nullptr;
  static ExtendedCallback UserCallback = nullptr;
}

//usage
struct MyTag1 {} ;// create any number of tags
//probably, we need to define static data
void* CallbackHolder<MyTag1>::UserData = nullptr;
ExtendedCallback CallbackHolder<MyTag1>::UserCallback = nullptr;

Callback<MyTag1> c; // track lifetime as needed
Callback fn = &Callback<MyTag1>::Func;
addCallback(state, fn);


4) заморачиваемся с динамическими колбеками-трамплинами. их можно поддерживать динамически или сразу выделить пул из 100 колбеков. рекомендую гуглить по словам trampoline, thunk
на этом форуме тоже замечательно гуглится: http://rsdn.ru/forum/cpp.applied/5116247.flat
Автор: uzhas
Дата: 28.03.13

суть thunk в том, что он содержит секцию для хранения void* (доп данных) + расширенный колбек и содержит ассемблерный код, который перевызывает расширенный кол-бек со всеми данными
метакод
typedef void(*ExtendedCallback)(void * internalState, Data * data, void* userData);

struct ThunkData
{
  <executable code>
  void* UserData;
  ExtendedCallback UserCallback;
};

ThunkData* data = ...; <- get from pool or allocate somehow
data->UserData = myData;
data->UserCallback = mySuperCallback;
Callback fn = (Callback)(&data); <--- pointer to executable code inside thunk
addCallback(state, fn);


успехов