Здравствуйте, VladD2, Вы писали:
ВВ>>Какое-то описание есть здесь. Причем это не самый эффективный алгоритм.
VD>Сдается мне, что это в данном случае не причем.
Честно, не хочется тут особо спорить. Помнится, есть более подробное описание этого в Inside SharpDevelop. Была еще и интересная книжка про написание текстовых редакторов, но ссылки не приведу, так как ее надо искать, а интернет мне на работе урезали за то, что порнуху качал.
ВВ>> Скорость по большому счету упирается в отрисовку.
VD>Редактирования? Да.
Кстати, а почему для рисования TextRenderer не используется? Или он совсем недавно появился.
ВВ>>Не, ну я же не против абстракций. Собственно, я вообще не пытаюсь критиковать реализацию.
VD>Кстати, я не против критики. Я очень за критику. Я только хочу, чтобы она была продуманной. А то у меня со временем ужасные проблемы и не хочется убивать его на борьбу с догмами. (не обижайся) По этому если ты показывашь пальцем и говоришь, "вот это мне кажется странным (глупым, непродуманным...)", я постораюсь разобраться и подумать не ошибся ли я. Возможно даже переосмыслить свою позицию. Но когда все сводится к "ой, а не много ли тут памяти расходуется", то разговаривать то в общем-то не очем. Ведь предмет разговора не определен.
ОК, я понял. "Мне кажется странным, что работа со строками ведется в лоб, а не используется какой-либо из алгоритмов, позволяющих эффективно модифицировать строки". Так лучше?
ВВ>>На самом деле я пытался въехать во что упирается работа с текстами только по-строчно. Ведь все-таки string[] — это скорее _представление_ данных, чем сам данные.
VD>Во что упирается? Одна строка занимается, другая освобождается. В итоге мы имеем новую строку у которой длинна больше или меньше. ЖЦ при одной из сборок мусора сожмет кучу и мы заплатим только за разницу. Ну, еще мы заплатим временем затрачиваемым ЖЦ на работу. Но ведь мы уже оговорились, что со скорость воде как проблем нет? Далее какое-то место уйдет на хранение команы. Но это плата за возможность сделать анду и реду. Все промежуточные команды опять же подберет ЖЦ. Если вдруг когда-то хранение команд покажется черезчур накладным, то можно сбросить их на диск. Но вот пока что мне не кажется это нужным (хотя думл я об этом еще когда проектирваол редактирование).
Я немножко не об этом. Бог с ней, с памятью. Непонятно почему данные хранятся как, фактически, массив строк. Это было наиболее удобным/эффективным решением? Потому что на настоящий момент по крайней мере одна проблема имеет место быть — то вся работа со стилями как бы "привинчена" к конкретной строке, что несколько неудобно.
ВВ>>Да, согласен. Но чем gap buffer этому мешает?
VD>А что он мне даст? Читаем из твой ссылки:
VD>A gap buffer is a structure that models a string but allows relatively
VD>efficient insertion of text somewhere in the middle.
VD>У меня есть проблемы с производительностью? А вот на это efficient прийдется потратить память чтобы организовать дыры.
Ну ты же не жалуешься на то, что List<String> жрет слишком много памяти по сравнению со string[]. А здесь аналогия примерно такая же — да, мы оставляем дыры, тратим лишние байты, но благодаря этому можем делать in-place модицирование строки. Впрочем, достаточно об этом.
Кстати, неплохой идеей было бы как-то выделить низкоуровевый код отвечающий за работу с текстом — как это сделано в шарп-девелопе например. Чтобы при желании, если например потребуется сделать на основе Rsdn.Editor редактор для сверх-больших файлов можно было бы легко и просто это участок поменять.
VD>Ты забавно мыслиь. Ты пыташся сравнить работу редактора с (внимание!) интерфейсом Сцинтилы.
Если сравнить интерфейсы (а у Сцинтилы он весь из сообщений в стиле Виндовс стостит), то уверяю тебя интерфейс Rsdn.Editor куда проще. От част просто потому, что в нем не реализованы некторые вещи
, а от части потому, что нет необходимости возиться с низкоуровневыми абстракциями вроде char* и т.п.
А чем отличается "низкоуровневая абстракция" char* от System.String? Наличием звездочки?
VD>Например, я сразу ввел понятие координат и пересчеты между координатами представления и документа. В синтиле этого нет. Казалось бы проще... Но на самом деле разбираясь все время надо понимать, что вот этот int — это номер строки в документе, а вот этот — это в колонка в представлении. В итоге сам черт ноку сломит. То же самео с командами. Команда Сцинтилы — это один класс с кучей полей которые используются в разных случаях. У меня это набор классов которые используются только там где это возможно и нужно. Причем для большинства классов у меня есть визуализация в отладчике. В то же время в сцинтиле одно преобразование из/в utf-8 и хнанение байтов стилей вперемешку с байтами текста так шифрует суть происходящего, что даже строку то увидеть не возможно. Я же четко отделил стили от текста и храню его в виде простой строки.
Дык или я чего-то не понял или текст у тебя все-таки хранится не в виде простой строки, а виде _массива_ строк.
VD>>>Теперь о реализации. В Сцинтиле, точно так же как и в Rsdn.Editor применяются команды редактирования. Разница только в том, что у меня разные типы команд описываются разными классами и составляют иерархию:
VD>>>VD>>>Command - абстрактный
VD>>> MultiCommand
VD>>> ModifyTextCommand - абстрактный
VD>>> InsertCommand
VD>>> DeleteCommand
VD>>> UpdateCommand
VD>>>
VD>>>в которой все конкретные (не абстрактные) классы реализуют ICommand.
ВВ>>А зачем?
VD>Затем, чтобы видеть что рельно происходит. Чтобы отделять действия по вставке от действий по редактированию. Прицип действия моей команды очень прост. У любой команды можно вызвать ICommand.Execut() и ты получишь а) действия связанные с командой, б) команду обратную этой (то есть если выполнить полученную команду, то действия предыдущей будут откачены). А почему иерархия классов, а не "все в одном"? Дык между прочим InsertCommand должна хранить текст, DeleteCommand только координаты удаляемого текста, а UpdateCommand и то и другое. Ну, а MultiCommand вообще должны хранить список команд которые нужно выполнить как единую транзацию. Так что это Сцинтила расходует память по напрасну, так как ее команда всегда хранит "все что нужно".
VD>Но делал иерархию я не для этого. Иерархия позволяет хорошо отделить логику. В купе с наследованием реализации, которое позволяет выделить общую логику, это позволяет очень хоршо отделить разную логику друг от дурга и в то же время получить отличную абстаркцию.
А как будет в дальнейшем расширяться функциональность? Т.е. ты описал через эти интерфейсы примитивные операции, но помимо них будут и другие — да и собственно уже есть. Почему нет, например, SetStyleCommand?
Я не против идеи, идея интересная, но зачем 1) выставлять наружу детали реализации (всякие InsertCommand, DeleteCommand и пр.); это должны ИМХО быть частные реализации, иначе представь как загрузится АПИ если "дописать" сюда команд, 2) такой подход должен быть наверное общим, а не избирательным, а то придется смотреть что реализовано в качестве команды, а что в качестве DocumentRow.XXX.
VD>Возможно отчасти потому, что Сцинтиле много лет и всей все уже отработно, а у меня работа со стилями откровенно не доделана.
Вот, было подозрение

И наверное лучше сначала доделать.
VD>При этом исчезает еще одна проблема. Ты не ограничен количеством битов отводимых на стиль. Размер массива может быть любым! А вот в Сцинтиле, если мне не изменяет память, количество стилей не дожно привышать 16.
Да ладно уж, там почти целый байт. Кстати int32 мне тоже кажется небольшим излишеством — хотелось бы например иметь возможность ассоциировать какую-нибудь custom-информацию со строкой (например, для browser-like навигации по тексту), не отводить же для этого очередной Int?
VD>Понятно, что для одного-двух язяков не трудно написать стайлер вручную. В Сцинтиле все стайлеры написаны вручную (Уроды, блин! Правда есть редакторы на базе Сцинтилы которые имеют свои генераторы стайлеров.). Но мы не индусы
. Так что нужно сделать генератор лексеров. Самый простой и продуктивный путь — это выдрать генератор детерминированного конечного автомата (ДКА) из CocoR и изменив в нем кодогенерацию порождать эффективные стайлеры вместо CocoR-ного Scanner-а.
А как ты себе представляешь генератор лексеров? Т.е. чего он будет генерировать и на основе чего? У меня кстати была в свое время сделать что-то типа враппера над кокой — т.е. на основе простой описанной в ХМЛ грамматике генерится EBNF-грамматика для коки, на основе которой уже динамически собирается парсер. Однако особых бенефитов такой способ не даст, а гемора будет не много.
Мне казалось, что не так сложно написать ручками лексер который подойдет для большинства грамматик, а если уж будет что-то слишком навороченное, то можно и свой написать, так как всевозможные случаи все равно не предусмотришь.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>