Внутри этой функции вызывается коллбек-функция 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
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Аноним, Вы писали:
А>вообщем не вижу проблемы.
Как известно, главное в умении ходить сквозь стены -- не видеть препятствий
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, rg45, Вы писали:
R>Я несколько лет назад сталкивался с аналогичной проблемой: как функциональный объект превратить в указатель на функцию. Был применен грязный хак, но решение получилось вполне рабочее. В двух словах идея в следующем: в динамической памяти выделяется блок(блоки) исполняемого кода. Этот код полностью соответствует коду обычной функции, которая делегирует переданные ей параметры функтору, this которого, как и вызываемой функции-члена, были "прошиты" непосредственно в коде. Адреса этих блоков памяти интерпретирповались как точки входа в функции с соответствуюшими сигнатурами. Формирование таких блоков — задача интересная сама по себе, если заинтересует, могу изложить мое решение.
В принципе, с практической точки зрения, достаточно иметь пул таких функций какого-то предопределённого размера. И просто, когда такая функция нужна, аллокировать функцию из пула, прописывать в неё параметры, вызывать scandir, ну а потом возвращать функцию в пул.
По идее число функций из пула нужных одновременно довольно ограниченно по жизни, кроме того, его можно ограничить при помощи семафора. Типа если больше 16 потоков хочет одновременно позвать scandir, то все, начиная с 17-го ждут своей очереди...
Именно ткие рассуждения привели меня к такому вот решению
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ., Вы писали:
.>Ты начни с того, насколько это переносимо, будет ли это работать с DEP?
В рамках одной архитектуры процессора — вполне переносимо (другими словами, под каждую архитектуру нужно писать свои переходники, как сделано в ATL). С DEP работать будет, если нормально реализовать (достаточно выделять память под санки через VirtualAlloc c PAGE_EXECUTE_READWRITE).
Здравствуйте, vitalyk, Вы писали:
V>Здравствуйте, ., Вы писали:
.>>Ты начни с того, насколько это переносимо, будет ли это работать с DEP?
V>В рамках одной архитектуры процессора — вполне переносимо (другими словами, под каждую архитектуру нужно писать свои переходники, как сделано в ATL). С DEP работать будет, если нормально реализовать (достаточно выделять память под санки через VirtualAlloc c PAGE_EXECUTE_READWRITE).
Еще есть проблема с разными размерами указателей на данные и испоняемый код.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Еще есть проблема с разными размерами указателей на данные и испоняемый код.
Да вообще проблем много довольно. Например на PPC есть специальный регистр, который аддресует 64К памяти, к которой есть быстрый доступ. Компиляторы часто располагают там всякие нужные по ходу пьесы статические данные. Соответсвенно, если позвать функцию, а в регистре этом не то передать, то а-та-та будет. Так что приходится иметь в указателе на функцию два числа -- адрес кода и адрес, который должен оказаться в таком регистре. Ну а как в таких условиях рожать свой код -- вопрос тоде довольно прикольный
И совсем-совсем-совсем не портабл.
Когда я в прошлый раз в такую фигню упёрся, я в конце концов придумал как ничего не компилировать и иметь приемлемую производительность тем не менее.
Так что я бы компиляции избегал бы всеми ногами и руками
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, sokel, Вы писали:
S>Здравствуйте, Graf Alex, Вы писали:
GA>>Всем спасибо за разъяснение...
GA>>Сразу отвечаю на некоторые пункты, дабы не отвечать на каждое письмо в отдельности GA>>1) scandir — Единственный способ получить список файлов в линухе... во всяком случае из известных мне высокоуровневых. Да, тут явная ошибка в дизайне, но деваться мне некуда. По той же причине пнуть создателя я не могу
S>а чем glob не подходит?
Не нашел для C++
Здравствуйте, Graf Alex, Вы писали:
GA>Здравствуйте, sokel, Вы писали:
S>>Здравствуйте, Graf Alex, Вы писали:
GA>>>Всем спасибо за разъяснение...
GA>>>Сразу отвечаю на некоторые пункты, дабы не отвечать на каждое письмо в отдельности GA>>>1) scandir — Единственный способ получить список файлов в линухе... во всяком случае из известных мне высокоуровневых. Да, тут явная ошибка в дизайне, но деваться мне некуда. По той же причине пнуть создателя я не могу
S>>а чем glob не подходит? GA>Не нашел для C++
Упс.. не там искал
E>Можно, кстати, заставить клиентов ждать на семафоре со счётчиком равным ThunkFunc::TotallRegisteredCollbaks() -- тогда всё будет вообще хорошо.
Сдаётся мне что решение с семафором будет потенциальным источником дедлоков. Из интерфейса функции-то не видно что кто-то с кем-то тут будет синхронизироваться, и если callback-функции будут в свою очередь вызывать scandir, то могут быть траблы. Так что имхо уж лучше TLS или thunk-и.