Внутри этой функции вызывается коллбек-функция filter для того, что бы узнать подходит ли нам некоторый файл или нет...
Есть так же вспомогательная функция:
int fnmatch(const char *pattern, const char *string, int flags);
Первый параметр — маска файла, второй параметр — имя файла которое нужно проматчить по маске...
Задача: написать функтор, в который я бы мог положить маску, и что бы этот функтор вел себя как обычная сишная функция. Другими словами как мне пробросить маску файла в функцию fnmatch?
PS Смотрел в сторону pointer_to_binary_function, но так и не вкурил как это использовать
Непонятно. Если я правильно понял, что filter — это собственная (не библиотечная) функция, то что мешает из нее звать fnmatch с требуемыми параметрами?
Раз уж scandir ожидает указатель на функцию, то ничего не попишешь — придется передавать именно указатель на функцию
Ну а дополнительный параметр дл этой функции можно подсунуть например вот так:
GA>Внутри этой функции вызывается коллбек-функция filter для того, что бы узнать подходит ли нам некоторый файл или нет...
Колбеки без контекста — зло. Отыщи такой вариант, в котором int (*filter)(struct dirent const *, void* context).
GA>Задача: написать функтор, в который я бы мог положить маску, и что бы этот функтор вел себя как обычная сишная функция. Другими словами как мне пробросить маску файла в функцию fnmatch?
Или с помощью шаблонов, или с помощью глобальных переменных.
GA>PS Смотрел в сторону pointer_to_binary_function, но так и не вкурил как это использовать :( :???:
> Задача: написать функтор, в который я бы мог положить маску, и что бы > этот функтор вел себя как обычная сишная функция. Другими словами как > мне пробросить маску файла в функцию fnmatch?
А никак.
Только если глобальные переменные, либо ассемблерные хаки.
Или возможно есть что-нибудь в dirent, что позволяет протащить параметр?
И вообще, пнуть больно писателя такой функции, чтобы параметр можно было протаскивать, либо самому переписать.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
<>
scandir — это пример ошибки в дизайне. Как, кстати, и некоторые другие POSIX-овые функции.
Хороший дизайн функции с колбеками предполагает передачу пользовательского параметра.
Здесь же этого нет.
GA>PS Смотрел в сторону pointer_to_binary_function, но так и не вкурил как это использовать
Его — никак. Это С++ный шаблон, превращающий двухаргументную функцию в объект класса, унаследованного от std::binary_function (это нужно для вывода типов).
Тебе же нужна JIT-компиляция переходника, превращающего замыкание функции на первый аргумент в обычную функцию.
Можешь вдохновиться примером ATL CStdCallThunk (файл <atlstdthunk.h> из ATL7+).
Правда, придётся доработать их паяльником, т.к. они заточены под конвенцию __stdcall, позволяющую напихать дополнительные аргументы в стек и сделать переход к функции в расчёте на то, что стек она почистит.
Для __cdecl же — в общем случае переходник сделать вообще невозможно, а для фиксированного количества аргументов придётся поплясать.
Здравствуйте, Vamp, Вы писали:
V>Непонятно. Если я правильно понял, что filter — это собственная (не библиотечная) функция, то что мешает из нее звать fnmatch с требуемыми параметрами?
А мешает то, что функция scandir должна вызываться из куска кода, который вызывается из разных потоков и с разной маской...
Т.о. маску нельза положить ни в глобальную ни в статическую переменную...
Сразу отвечаю на некоторые пункты, дабы не отвечать на каждое письмо в отдельности
1) scandir — Единственный способ получить список файлов в линухе... во всяком случае из известных мне высокоуровневых. Да, тут явная ошибка в дизайне, но деваться мне некуда. По той же причине пнуть создателя я не могу
2) проект кроссплатформенный и хаков писать я не буду. Даже несмотря на то, что код со scandir'ом ограничен #ifdef LINUX
3) поскольку код многопоточный — использование глобальных и статических переменных отпадает
4) Реализовал я методом вытягивания всех файлов, а потом отсеивания лишних все той же fnmatch. Тут же я задал вопрос скорее из любопытства, возможно ли такое вообще
Здравствуйте, Graf Alex, Вы писали:
GA>1) scandir — Единственный способ получить список файлов в линухе... во всяком случае из известных мне высокоуровневых. Да, тут явная ошибка в дизайне, но деваться мне некуда. По той же причине пнуть создателя я не могу
Не единственный Вместо этого дурного дизайна (возвращающего указатель на массив указателей на dirent, которые потом нужно поштучно грохнуть — что тоже сказочно)
Вызывать opendir() / readdir_r() / closedir(), самому же себе фильтровать, сохранять в подходящем контейнере и сортировать в своё удовольствие.
А если сортировка не нужна, то и сохранять необязательно.
Если очень хочется высокоуровневости — ну перепиши scandir по мотивам.
На чистом Си это, конечно, мучительно будет. На С++ попроще.
Здравствуйте, Graf Alex, Вы писали:
GA>Тут наткнулся на проблему....
GA>Другими словами как мне пробросить маску файла в функцию fnmatch?
Если scandir работает (в том числе и вызывает колл-беки) в контексте одного потока (что наверняка так), проблема решается использованием thread local storage. В случае с Windows выглядело б это примерно так:
...
// Где-то во время инициализации...
DWORD dwSlot = ::TlsAlloc();
...
// Наша функция-фильтрint filter( const struct dirent * )
{
const char * szPattern = reinterpret_cast<const char *>( ::TlsGetValue( dwSlot ) );
// Используем szPattern, в том числе и отправляем его в fnmatch
// ...
}
...
// Сохраняем текущее значение tls слота на случай, если кто-то выше по стеку тоже его использует (в том числе и этот фрагмент кода)void * pOldTlsValue = ::TlsGetValue( dwSlot );
// Задаем маскуconst char * szPattern = "*.txt";
::TlsSetValue( dwSlot, const_cast<char *>( szPattern ) );
// Вызываем scandir - filter получит маску из слота
::scandir( ..., ..., &::filter, ... );
// Восстанавливаем старое значение слота
::TlsSetValue( dwSlot, pOldTlsValue );
GA>Внутри этой функции вызывается коллбек-функция filter для того, что бы узнать подходит ли нам некоторый файл или нет...
Конечно удобным и регулярным решением является передача параметров через tread loacl переменную.
Но, если охота извращаться, то можно устроить такой вот хак (пишу из головы, так что это С++ "приблизительно"):
Можно, кстати, заставить клиентов ждать на семафоре со счётчиком равным ThunkFunc::TotallRegisteredCollbaks() -- тогда всё будет вообще хорошо. Только ещё надо аллокацию/освобождение колбэка сериализовать...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: функтор как указатель на функцию
От:
Аноним
Дата:
24.04.08 07:02
Оценка:
Здравствуйте, Graf Alex, Вы писали:
GA>Тут наткнулся на проблему....
GA>Есть функция, которая делает список файлов в указаной директории... GA>
GA>Внутри этой функции вызывается коллбек-функция filter для того, что бы узнать подходит ли нам некоторый файл или нет...
GA>Есть так же вспомогательная функция: GA>
GA>int fnmatch(const char *pattern, const char *string, int flags);
GA>
GA>Первый параметр — маска файла, второй параметр — имя файла которое нужно проматчить по маске...
GA>Задача: написать функтор, в который я бы мог положить маску, и что бы этот функтор вел себя как обычная сишная функция. Другими словами как мне пробросить маску файла в функцию fnmatch?
а чем не угодил просто функтор с оператором ()(const struct dirent *)? или нет возможности править scandir
чем плох boost::function + boost::bind?
Здравствуйте, Аноним, Вы писали: А>а чем не угодил просто функтор с оператором ()(const struct dirent *)? или нет возможности править scandir
Как я уже писал, функция scandir — библиотечная... И никто переписывать ее не будет А>чем плох boost::function + boost::bind?
Может, конечно и не плох... но как им пользоваться я не знаю...
с примером — велкам
Здравствуйте, Graf Alex, Вы писали:
GA>Всем спасибо за разъяснение...
GA>Сразу отвечаю на некоторые пункты, дабы не отвечать на каждое письмо в отдельности GA>1) scandir — Единственный способ получить список файлов в линухе... во всяком случае из известных мне высокоуровневых. Да, тут явная ошибка в дизайне, но деваться мне некуда. По той же причине пнуть создателя я не могу
Здравствуйте, Graf Alex, Вы писали:
GA>Задача: написать функтор, в который я бы мог положить маску, и что бы этот функтор вел себя как обычная сишная функция. Другими словами как мне пробросить маску файла в функцию fnmatch?
Я несколько лет назад сталкивался с аналогичной проблемой: как функциональный объект превратить в указатель на функцию. Был применен грязный хак, но решение получилось вполне рабочее. В двух словах идея в следующем: в динамической памяти выделяется блок(блоки) исполняемого кода. Этот код полностью соответствует коду обычной функции, которая делегирует переданные ей параметры функтору, this которого, как и вызываемой функции-члена, были "прошиты" непосредственно в коде. Адреса этих блоков памяти интерпретирповались как точки входа в функции с соответствуюшими сигнатурами. Формирование таких блоков — задача интересная сама по себе, если заинтересует, могу изложить мое решение.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Аноним, Вы писали:
А>а чем не угодил просто функтор с оператором ()(const struct dirent *)? или нет возможности править scandir А>чем плох boost::function + boost::bind?
Тем, что внутри функции scandir идет обращение к указателю на функцию, а не вызов функции-члена operator() функционального объекта. А о том, что scandir нельзя править, говорилось.
--
Справедливость выше закона. А человечность выше справедливости.
rg45 wrote:
> Я несколько лет назад сталкивался с аналогичной проблемой: как > функциональный объект превратить в указатель на функцию. Был применен > грязный хак, но решение получилось вполне рабочее. В двух словах идея в > следующем: в динамической памяти выделяется блок(блоки) исполняемого > кода. Этот код полностью соответствует коду обычной функции, которая > делегирует переданные ей параметры функтору, /this/ которого, как и > вызываемой функции-члена, были "прошиты" непосредственно в коде. Адреса > этих блоков памяти интерпретирповались как точки входа в функции с > соответствуюшими сигнатурами. Формирование таких блоков — задача > интересная сама по себе, если заинтересует, могу изложить мое решение.
Ты начни с того, насколько это переносимо, будет ли это работать с DEP?
А так, самое правильное решение — не использовать scandir, а сделать самому через opendir/readdir/closedir.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ., Вы писали:
R>> Я несколько лет назад сталкивался с аналогичной проблемой: как R>> функциональный объект превратить в указатель на функцию. Был применен R>> грязный хак, но решение получилось вполне рабочее.
.>Ты начни с того, насколько это переносимо, будет ли это работать с DEP?
С переносимостью очевидные проблемы. Я ж так и говорю: "грязный хак".
.>А так, самое правильное решение — не использовать scandir, а сделать самому через opendir/readdir/closedir.
+1
--
Справедливость выше закона. А человечность выше справедливости.