К сожалению, я прослойка, а "сторон" две: "снизу" у меня pChar'ы (которыми я кое-как управлять могу), а "сверху" pChar'ы неизвестной природы и string'и. Иногда мне нужно в "верхний" pChar присваивать "верхний" же string.kipar писал(а):При работе с данными "со стороны" я бы копировал их сразу в "свой" string и дальше работал только с ним.
Строковый зоопарк
Модератор: Модераторы
-
MageSlayer
- постоялец
- Сообщения: 216
- Зарегистрирован: 07.09.2006 12:30:44
К сожалению, я прослойка, а "сторон" две: "снизу" у меня pChar'ы (которыми я кое-как управлять могу), а "сверху" pChar'ы неизвестной природы и string'и. Иногда мне нужно в "верхний" pChar присваивать "верхний" же string.
Как насчет следующего извращения?
То есть объявить свой тип строки и к нему несколько фабрик/методов для конвертации.
Подсчет ссылок будет работать и типизация будет отлавливать проблемы.
Код: Выделить всё
TUtf8string = object
private
F:string;
end;
function S(const a:TUtf8string):TUtf8string;
begin
end;
begin
s('sdfsdf'); //здесь будет ошибка типизации
end.
and писал(а):а "сверху" pChar'ы неизвестной природы
А что если попытаться экспериментально определить, какие из них какие? Если точек, в которых приходится оперировать с этими PChar'ами (процедур, функций, в т.ч. коллбэков) -- ограниченное количество, и если предположить, что в одни и те же функции поступают PChar'ы одинаковой природы -- вполне можно выяснить эту "природу" экспериментально на некотором количестве примеров, и записать себе в комментарии, чтобы потом освобождать эти PChar'ы правильно.
Например, можно в каждой точке взаимодействия посчитать длину PChar от начала до нулевого байта и сравнить с четырёхбайтным беззнаковым целым, предшествующим указателю. Даже если PChar начинается с самого указателя, и перед ним чужая память, вероятность того, что последние четыре байта этой памяти всегда совпадают с длиной нашей строки довольно мала. Таким образом, после некоторого числа экспериментов природа PChar'а, попадающего в конкретную функцию прослойки может быть определена, при условии что эта "природа" постоянна для данной функции.
Добавлено спустя 3 минуты 49 секунд:
MageSlayer писал(а):Что-то странно, что никто задается вопросом как кроссплатформенно нормализировать строки в fpc/lazarus.
Самому пока не очень-то надо, но вопрос остается.
Угу, и у меня такая же ситуация. Проблема пока смягчается тем, что Windows (пока это большая часть моих пользователей) нормализует юникод в NFC, а в Linux библиотеки стараются не менять нормальную форму. Поэтому сравнение и поиск подстроки с "й" и "ё" чудом работают. Но в Mac OS X используется NFD, т.е. стоит хотя бы одному пользователю под Mac OS X нагенерировать файлов, и начнётся кошмар
MageSlayer писал(а):Тупым поиском по исходникам fpc находится только какая g_utf8_normalize.
packages/gtk2/src/glib/gunicode.inc:236: g_utf8_normalize
Это внешняя функция из glib. Теоретически и в Qt, и в WinAPI тоже есть функции нормализации, которые можно использовать. Т.е. для GUI приложений, где зависимость от графического тулкита уже есть, можно относительно быстро создать реализацию для большинства виджетсетов. Ещё есть ICU4PAS - обёртка к библиотеке ICU, но это внешняя разделяемая библиотека довольно ощутимого размера, которую не очень хочется таскать за собой.
MageSlayer писал(а):Есть у кого наработки?
Надо же как-то сравнивать строки, да поиск подстроки в utf8 тоже никто еще не отменял!
Нативных наработок без внешних зависимостей не знаю. Если кто-нибудь найдёт или напишет, да ещё и сообщит на форуме -- будет просто замечательно.
2MageSlayer: Не понял суть "извращения". Что с ним делать-то?
В принципе, что делать - более-менее придумалось. Жаль только, что через ж приходится обходить грабли, возникшие на таком, казалось бы, ровном месте.
Добавлено спустя 12 часов 29 минут 2 секунды:
2MageSlayer: А, ну да, я не тормоз. Сам почти так и сделал (но внутри не string, а pChar заведомо известной мне разновидности), и только потОм закралась мысль "где-то я это уже видел" :-)))
И у меня s('sdfsdf') ошибку типизации не вызывает: я перегрузил операторы присваивания со string'ом и pChar'ом. Теперь другая проблемка: не могу nil присвоить. Точнее, не знаю, предыдущее значение - это валидное значение указателя (которое нужно освободить) или просто неинициализированный мусор (который даст AV при попытке освобождения).
Ограниченное, конечно. А вот мест, _откуда_ в эти точки приходят данные, намного больше.Odyssey писал(а):Если точек, в которых приходится оперировать с этими PChar'ами (процедур, функций, в т.ч. коллбэков) -- ограниченное количество
Ой, не люблю я в программе опираться на предположения...Odyssey писал(а):и если предположить
Увы! pChar - одно из полей "нижней" структуры. Кто, когда и чем заполнял конкретный её экземпляр - мне неведомо.Odyssey писал(а):в одни и те же функции поступают PChar'ы одинаковой природы
В принципе, что делать - более-менее придумалось. Жаль только, что через ж приходится обходить грабли, возникшие на таком, казалось бы, ровном месте.
Добавлено спустя 12 часов 29 минут 2 секунды:
2MageSlayer: А, ну да, я не тормоз. Сам почти так и сделал (но внутри не string, а pChar заведомо известной мне разновидности), и только потОм закралась мысль "где-то я это уже видел" :-)))
И у меня s('sdfsdf') ошибку типизации не вызывает: я перегрузил операторы присваивания со string'ом и pChar'ом. Теперь другая проблемка: не могу nil присвоить. Точнее, не знаю, предыдущее значение - это валидное значение указателя (которое нужно освободить) или просто неинициализированный мусор (который даст AV при попытке освобождения).
-
MageSlayer
- постоялец
- Сообщения: 216
- Зарегистрирован: 07.09.2006 12:30:44
and писал(а):2MageSlayer: А, ну да, я не тормоз. Сам почти так и сделал (но внутри не string, а pChar заведомо известной мне разновидности), и только потОм закралась мысль "где-то я это уже видел"))
Все верно, так все и делают
Для меня загадка только почему команда FPC/Lazarus упорно не хотят пойти этим путем.
and писал(а):И у меня s('sdfsdf') ошибку типизации не вызывает: я перегрузил операторы присваивания со string'ом и pChar'ом.
А вот это - зря. Операторы кодировки знать не могут, так что это ты просто обратно отключил типизацию.
А надо как все - "по камешкам". Сделать несколько разных функций конвертации из PChar и string в этот объект.
Вот тогда все будет нормально.
and писал(а):Теперь другая проблемка: не могу nil присвоить. Точнее, не знаю, предыдущее значение - это валидное значение указателя (которое нужно освободить) или просто неинициализированный мусор (который даст AV при попытке освобождения).
Лучше использовать внутри string. Компилятор пускай думает.
Тебе только правильно сконструировать строку надо будет.
И использовать еще одно спец. значение nil плюс к пустой строке - не советую.
Делай пустую строку эквивалентной nil.
null/nil значения внутри типа - вообще безусловное зло.
Эта идея могла прийти только в больную голову.
А меня не кодировка волнует :-)MageSlayer писал(а):А вот это - зря. Операторы кодировки знать не могут, так что это ты просто обратно отключил типизацию.
И в чём глубокая сакральная разница между конвертацией внутри функции и внутри оператора? В том, что на каждую кодировку источника я могу свою функцию написАть? Так - повторюсь - кодировка меня не волнует совершенно.MageSlayer писал(а):А надо как все - "по камешкам". Сделать несколько разных функций конвертации из PChar и string в этот объект.
Не хочу терять совместимость с pChar'ом. Да и 12 байт лишних жалко :-)MageSlayer писал(а):Лучше использовать внутри string. Компилятор пускай думает.
-
MageSlayer
- постоялец
- Сообщения: 216
- Зарегистрирован: 07.09.2006 12:30:44
and писал(а):А меня не кодировка волнует
Странное у вас приложение тогда, ей-богу.
Ни в лог не записать, не экран нормально не вывести.
Вы в уме код отлаживаете?
and писал(а):И в чём глубокая сакральная разница между конвертацией внутри функции и внутри оператора? В том, что на каждую кодировку источника я могу свою функцию написАть?
Именно в этом. В том есть логика - на каждую кодировку строки - своя функция "нормализации".
По-крайней мере до наступления того светлого будущего, когда у однобайтовых кодировок будет отдельный тип от utf8.
and писал(а):Не хочу терять совместимость с pChar'ом. Да и 12 байт лишних жалко
Хозяин - барин, конечно.
Только зачем тогда использовать FPC?
Си тут больше в тему.
MageSlayer писал(а):К сожалению, я прослойка, а "сторон" две: "снизу" у меня pChar'ы (которыми я кое-как управлять могу), а "сверху" pChar'ы неизвестной природы и string'и. Иногда мне нужно в "верхний" pChar присваивать "верхний" же string.
Если вы прослойка, договоритесь с верхними об интерфейсах. Пусть вам "верхние" методы дадут для присвоение String -> PChar. Голова болеть сразу перестанет. Что там за PChar? Как он появился? Как его диспосить - не должно быть вашей проблемой.
Я без ошибок пишу :-DDDMageSlayer писал(а):Вы в уме код отлаживаете?
Да ужЕ не нужно: разрулил обёртыванием в object и перегрузкой операторов.vada писал(а):договоритесь с верхними об интерфейсах. Пусть вам "верхние" методы дадут для присвоение
Всем спасибо, практическая проблема, в общем-то, решена. Осталось только небольшое теоретическое недоумение :-)
and писал(а):разрулил обёртыванием в object и перегрузкой операторов.
Т.е. у вас получилось что-то типа string, но с гораздо большим overhead. Не проще ли было использовать string?
У string'а я не могу управлять временем жизни (если, конечно, не прибегать к хакам вроде ручной правки refCount). И повторяю,Max Rusov писал(а):Не проще ли было использовать string?
Угадайте, куда я влечу, когда мне "снизу" придёт структура с pChar'ом, а я буду ждать в этом месте string?and писал(а):Не хочу терять совместимость с pChar'ом. Да и 12 байт лишних жалко :-)
and писал(а):У string'а я не могу управлять временем жизни (если, конечно, не прибегать к хакам вроде ручной правки refCount).
Ну и не надо. Runtime сам прекрасно управляет.
and писал(а):Не хочу терять совместимость с pChar'ом.
String совместим с PChar. Причем - в обе стороны.
and писал(а):Да и 12 байт лишних жалко
А Ваш object, в который Вы PChar "обёртываете" - он байты не занимает?
and писал(а):Угадайте, куда я влечу, когда мне "снизу" придёт структура с pChar'ом, а я буду ждать в этом месте string?
Без понятия. Я вообще не понимаю сути Вашей проблемы. За 15 лет программирования на Delphi у меня ни разу не возникло подобных вопросов.
Не уверен. Особенно при передаче в/из dll.Max Rusov писал(а):Runtime сам прекрасно управляет.
Да ну! 8-O То есть, если я скажу FreeMem(pChar(s)), у меня всё будет в порядке?Max Rusov писал(а):String совместим с PChar. Причем - в обе стороны.
А с чего ему байты занимать-то? В нём ничего, кроме pChar, нету. Перегруженные операторы - да, чуть-чуть кода. Но _один_ раз, а не на каждый экземпляр.Max Rusov писал(а):А Ваш object, в который Вы PChar "обёртываете" - он байты не занимает?
Всё когда-нибудь бывает впервые :-) Я тоже серьёзно писать начал на D1 (TP+TV до этого можем опустить для краткости), и тоже о такую ерунду впервые споткнулся, ну и что?Max Rusov писал(а):За 15 лет программирования на Delphi у меня ни разу не возникло подобных вопросов.
Я заметил :-)))Max Rusov писал(а):Я вообще не понимаю сути Вашей проблемы.
Видимо всетаки проблемы не в зоопарке строк а в менеджере памяти.
В JAVA я зачастую даже не парюсь с дистроями объектов. Например в методе создаю объект который автоматически дистроится при выходе из метода. Скидывается со стека и душится автоматом. Очччччень удобно.
С другой стороны с дуру можно себе ногу отстрелить примерно такой работой со строкой:
На каждом шаге цикла захватывается новый кусок памяти и старый освобождается.
В JAVA я зачастую даже не парюсь с дистроями объектов. Например в методе создаю объект который автоматически дистроится при выходе из метода. Скидывается со стека и душится автоматом. Очччччень удобно.
С другой стороны с дуру можно себе ногу отстрелить примерно такой работой со строкой:
Код: Выделить всё
String S = "";
for (int i=1; i<=10000; i++) {
S = S + "A";
}
На каждом шаге цикла захватывается новый кусок памяти и старый освобождается.
and писал(а):>Runtime сам прекрасно управляет.
Не уверен. Особенно при передаче в/из dll.
Даже в этом случае, при соблюдении определенных условий. Но в DLL всегда лучше передавать PChar, благо:
and писал(а):>String совместим с PChar. Причем - в обе стороны.
Да ну! 8-O То есть, если я скажу FreeMem(pChar(s)), у меня всё будет в порядке?
Совместим - означает, что вы можете одному присвоить другой, а не писать все что Вам вздумается. Я еще +100500 способов знаю, как уронить программу - и что?
and писал(а):>А Ваш object, в который Вы PChar "обёртываете" - он байты не занимает?
>А с чего ему байты занимать-то? В нём ничего, кроме pChar, нету. Перегруженные операторы - да, чуть-чуть кода. Но _один_ раз, а не на каждый экземпляр.
Если это Class - то он аллоцируется в куче и занимает гораздо больше памяти, чем overhead string'а. Если Object на стеке - другой вопрос. Не знаю, поддерживает ли Object перегрузку операторов - не интересовался...
Добавлено спустя 1 минуту 59 секунд:
vada писал(а):На каждом шаге цикла захватывается новый кусок памяти и старый освобождается.
Ну так и в FPC так будет. "Вы так не делайте"
