Здравствуйте, adontz, Вы писали:
A>Ой, долго объяснять как это будет работать В любом случае если будут в целом положительные отзывы и я это напишу, то продукт будет бесплатный.
Видя, как вы интересуетесь парсерами классов в соседнем форуме, есть предположение, что всё же парсер
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
"Man feed machine
Machine feed man"
Peter Gabriel — OVO — The Tower That Ate People
Здравствуйте, c-smile, Вы писали:
CS>с точки зрения трудозатрат написание SERIALIZABLE(int var1); эквивалентно persist(ar,var1)
Не скажи...
Надо еще писать эту сериализуемую функцию ручками Всё же лишнии строки...
CS>и вся система получается а) гибче б) прозрачнее.
Не знаю как насчет гибче, но вряд ли прозрачнее. Наглядность теряется...
"Man feed machine
Machine feed man"
Peter Gabriel — OVO — The Tower That Ate People
Здравствуйте, adontz, Вы писали:
A>А вот мне это совершенно не нравиться Вручную вообще ничего не должно быть.
А другого способа просто нет. Теоретически (на практике не пробовал), можно конечно изобрести такую хэш функцию, которая будет нумеровать поля 1,2,3, и при добавлении нового в любое место — 4 и т.д. Но при этом придется с каждым классом передавать какую-то информацию об этой хеш-фукции.
A>Но в принципе можно сделать так. A>В XML и прочих форматах записывается непосредственно строка с именем типа/переменной. A>В двоичных форматах перед использованием типа делается оглавление вида A>
A>0: test<float>, fields
A> {
A> 0: int = var1
A> 1: float = var2
A> 2: std::string = str
A> };
A>
A>а далее идёт запись вида A>
A>0:
A> {
A> 0: 45;
A> 1: 3.67f;
A> 2: "qwerty"
A> }
A>
Это уже фактически получается словарь данных. Со словарем, да — это возможно. Но сама идея словаря мне не нравится. Если надо передать много-много объектов, то объем словаря значения не имеет. Если же надо часто передавать один объект, то начинаются заморочки. Передавать словарь каждый раз — накладно. Передавать один раз вначале — это уже организация stateful протокола для инициации сессий — тоже бодяга та еще. Указание на словарь в виде ссылки — это уже похоже на XML+DTD со всеми вытекающими.
Можно так же автоматически генерировать ID и писать их непосредственно в декларации полей (ни к коем случае не в дополнительный файл типа ресурсов!), но это уж точно будет препроцессор. Исходя из идеи сериализации чисто средствами C++, при условии сохранения компактности данных, ручное присвоение ID — это наименьшее из зол.
A>Для хранения номеров полей можно использовать схему типа UTF8 или даже действительно выделить 1 байт. Не будет же в одном классе больше чем 256 полей A>Для хранения номеров классов лучше не жадничать и выделить 4 байта, потому что больше чем 65536 классом может быть запросто, а 3 байта как-то лево.
И для того и для другого достаточно единого механизма (типа UTF8) — первые 7 бит — payload, старший бит — признак продолжения. Проверено, работает быстро и эффективно, как для беззнаковых, так и для знаковых целых. Кроме того, при этом не надо заботиться о порядке байт (для float/double — все-таки надо).
В общем, все зависит от конечной цели. Если надо достичь максимальной компактности бинарного потока плюс позиционной независимости данных, то надо соблюдать следующие правила:
1. Компактные ID для базовых и неполиморфных типов. Тип здесь передавать не надо вообще — ID является самодостаточным. Если вдруг поменялся тип со string на int — это в любом случае проблемы, даже если тип данных передается явно. Какие-то ситуации, конечно можно "разрулить" с передачей типов, но IMO овчинка выделки не стоит. Главное — позиционная независимость, а вольности с изменениями типов надо пресекать
2. Значения по умолчанию. Поля просто не сериализуются, если их значения равны значениям по умолчанию.
3. Имена типов нужны только для полиморфных классов, "поднимающихся" из входного потока через фабрики классов.
4. Дополнительная компактификация для типов bool. Семь bool'ов требуют как минимум 7*2=14 байт при "обычной" сериализации, в то время, как при компактной — достаточно двух. Здесь, однако, возникает проблема позиционной зависимости. Возможно, здесь лучше использовать Сишные битовые поля в явном виде.
В общем, идеальных решений здесь не существует ни для одного языка. В любом случае приходится чем-то жертвовать и идти на некий компромис.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, McSeem2, Вы писали:
MS>Это уже фактически получается словарь данных. Со словарем, да — это возможно. Но сама идея словаря мне не нравится. Если надо передать много-много объектов, то объем словаря значения не имеет. Если же надо часто передавать один объект, то начинаются заморочки. Передавать словарь каждый раз — накладно. Передавать один раз вначале — это уже организация stateful протокола для инициации сессий — тоже бодяга та еще. Указание на словарь в виде ссылки — это уже похоже на XML+DTD со всеми вытекающими.
Зря ты так о размере заботишься. У тебя подход исходящий из передачи по сети, но есть два момента:
Если не нужна версионность, то все эти заморочки с метками типов тоже не нужны и передаваться тогда будут только данные. Более того, версионность можно включать для отдельных классов.
Здравствуйте, Shady, Вы писали:
A>>Ой, долго объяснять как это будет работать В любом случае если будут в целом положительные отзывы и я это напишу, то продукт будет бесплатный. S>Видя, как вы интересуетесь парсерами классов в соседнем форуме, есть предположение, что всё же парсер
Это был ошибочный путь
Нет, парсера Си++ кода у меня ни в каком виде не будет, хотя бы потому что gcc и msvc в плане шаблонов оказались жутко не совместимы (сужу по gcc_xml) так что вариант с парсером отпадает. Более того мне идея с парсером не очень нравиться потому что это заметно увеличит время компиляции, а оно и так не маленькое.
Мое скромное имхо на данную тему:
1.
не надо новых парсеров исходных текстов, лучше обойтись сочетанием макросы + шаблоны.
2.
нужны несколько форматов файлов с соответствующим уклоном например:
*компактный бинарный
*быстрый бинарный
*портабельный (открытый)
и тп (сколько получицца).
3.
не надо заморачиваться с синтаксисом объявления (мне кажется проблемы с написанием operator<< или идентификаторов полей некритичны) наоборот "чрезмерная автоматизация" процесса через excessive template intantiations с замедлением компиляции в 10 раз (в чем признаются авторы s11n) это плохо.
4.
по возможности хочецца не жертвовать скоростью ради "полу-поддержки" версий и словарей данных.
Выход из ситуации для тех кто тут же завопит о том что неприемлемо давно известен —
в процессе активных изменений структуры все данные кладутся в открытый формат или внешнюю БД а к быстрым или компактным переходим когда изменения уже не так часты чтобы было лень делать экспорт/импорт. Для тех кому это не подходит в принципе скорее всего полумеры не помогут — им подавай OODB со всеми наворотами.
те. я присоединяюсь к c-smile
если бы была а) простая б) компактная в) независимая ни от чего система загрузки скажем 100 записей трех разных типов классов я бы принял это на вооружение
Здравствуйте, adontz, Вы писали:
A>Это был ошибочный путь A>Нет, парсера Си++ кода у меня ни в каком виде не будет, хотя бы потому что gcc и msvc в плане шаблонов оказались жутко не совместимы (сужу по gcc_xml) так что вариант с парсером отпадает. Более того мне идея с парсером не очень нравиться потому что это заметно увеличит время компиляции, а оно и так не маленькое.
Неудобство оно увеличивает... Сам сейчас буду приступать к мапированию данных на C++/Java. Похоже придется фигачит как-то парсером, чтоб был единый подход...
"Man feed machine
Machine feed man"
Peter Gabriel — OVO — The Tower That Ate People
Здравствуйте, SleepyDrago, Вы писали:
SD>1. SD>не надо новых парсеров исходных текстов, лучше обойтись сочетанием макросы + шаблоны.
Не будет.
SD>2. SD>нужны несколько форматов файлов с соответствующим уклоном например: SD>и тп (сколько получицца).
Будет.
SD>3. SD>не надо заморачиваться с синтаксисом объявления (мне кажется проблемы с написанием operator<< или идентификаторов полей некритичны) наоборот "чрезмерная автоматизация" процесса через excessive template intantiations с замедлением компиляции в 10 раз (в чем признаются авторы s11n) это плохо.
Не волнуйся я думаю уменьшение скорости сборки будет (не компиляции, а сборки) не более чем на 5-10%. Скорость компиляции практически не измениться.
SD>4. SD>по возможности хочецца не жертвовать скоростью ради "полу-поддержки" версий и словарей данных.
Здравствуйте, Shady, Вы писали:
S>Неудобство оно увеличивает... Сам сейчас буду приступать к мапированию данных на C++/Java. Похоже придется фигачит как-то парсером, чтоб был единый подход...
Здравствуйте, adontz, Вы писали:
A>С++ какой компилятор?
Кстати, может я подключусь к твоей разработке, так, чтоб идеями обмениваться.
Компиляторно независимо так сказать...
"Man feed machine
Machine feed man"
Peter Gabriel — OVO — The Tower That Ate People
Здравствуйте, Shady, Вы писали:
S>Здравствуйте, c-smile, Вы писали:
CS>>с точки зрения трудозатрат написание SERIALIZABLE(int var1); эквивалентно persist(ar,var1) S>Не скажи... S>Надо еще писать эту сериализуемую функцию ручками Всё же лишнии строки...
CS>>и вся система получается а) гибче б) прозрачнее. S>Не знаю как насчет гибче, но вряд ли прозрачнее. Наглядность теряется...
Если серализуемые данные это нечто типа пассивного DOM (т.е. описываемые в виде struct без методов) то вариант с SERIALIZABLE наверное имеет смысл.
Но если же данные — хотя бы немного активные то тут уже требуется явный доступ к последовательности загрузки/выгрузки. Управление состоянием объекта и пр.
Пример загрузки выгрузки HTML, например, не может быть описан в терминах SERIALIZABLE. HTML конечно не показатель но если говорить про XML то близко.
Также наверное важно наличие lookahead методов при восстановлении. Типа если есть child nodes создавать под них
контейнер, нет — и не надо. И т.д.
Здравствуйте, c-smile, Вы писали:
CS>Если серализуемые данные это нечто типа пассивного DOM (т.е. описываемые в виде struct без методов) то вариант с SERIALIZABLE наверное имеет смысл. CS>Но если же данные — хотя бы немного активные то тут уже требуется явный доступ к последовательности загрузки/выгрузки. Управление состоянием объекта и пр.
Если это расматривать с позиции мапирования базы данных, то подход с автоматизацией гораздо лучше. Object Database хотя бы...
CS>Также наверное важно наличие lookahead методов при восстановлении. Типа если есть child nodes создавать под них CS>контейнер, нет — и не надо. И т.д.
А что мешает это всё автоматизировать? Может не средствами языка, но парсингом?
"Man feed machine
Machine feed man"
Peter Gabriel — OVO — The Tower That Ate People
Здравствуйте, adontz, Вы писали:
A>Зря ты так о размере заботишься. У тебя подход исходящий из передачи по сети, но есть два момента: A>Если не нужна версионность, то все эти заморочки с метками типов тоже не нужны и передаваться тогда будут только данные. Более того, версионность можно включать для отдельных классов.
Нет, версионность — суксь, после версии пятой-шестой, сериализация превращается в нечитаемый и несопровождаемый спагетти-код. Позиционная независимость — рулез. Во-вторых, в моем частном случае таги позволяют значительно сократить объем данных. У каждого объекта — около 20 разных атрибутов, но в 90% слуаев используются лишь 1-2. Так что передавать просто данные — даже более накладно. И что-то мне подсказывает, что мой случай — не такой уж и частный.
A>Что мешает пропустить поток через обычный ZIP?
Во-первых, так и делается. Во-вторых, объем объектов в среднем — 300-500 байт, зипу там просто негде "разогнаться". В-третьих, сейчас проверил на наборе в 5000 объектов. Старый метод (жутко неэффективный) дает 16 мег, запаковывается в 1 мег. Компактная сериализация дает 1.5 мега, запаковывается в 480K. Ну это типа как JPEG (но без потерь) — априорные знания о сущности данных позволяет упаковать значительно сильнее, чем просто некий безликий Lempel-Ziv-Welch.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, Shady, Вы писали:
A>>С++ какой компилятор? S>Кстати, может я подключусь к твоей разработке, так, чтоб идеями обмениваться. S>Компиляторно независимо так сказать...
Я рад любой помощи, но на сегодняшний день я вижу несколько условий:
Целевой компилятор/среда это VC 7.1 (7.0 не подходит!). Упоминание о среде не лишне, поскольку на данном этапе я вижу желательность некоторого MSVC Add-in, который автоматизирует дополнительную настройку проектов избавляя от рутинной работы.
Проект выполняется в рамках другого, поэтому некоторые вещи менять не выйдет, например naming convention (она кстати ближе к STL'овской)
Тот, другой, проект, так же как и этот не были и никогда, пока я жив, не станут коммерческими (в том числе shareware).
Из приятного:
Я открыт для любых предложений, если что-то не нравиться, то мне никогда не лень сделать лучше.
Здравствуйте, McSeem2, Вы писали:
MS>Нет, версионность — суксь, после версии пятой-шестой, сериализация превращается в нечитаемый и несопровождаемый спагетти-код. Позиционная независимость — рулез. Во-вторых, в моем частном случае таги позволяют значительно сократить объем данных. У каждого объекта — около 20 разных атрибутов, но в 90% слуаев используются лишь 1-2. Так что передавать просто данные — даже более накладно. И что-то мне подсказывает, что мой случай — не такой уж и частный.
OK, буду думать как бы всё это хорошо метить.
A>>Что мешает пропустить поток через обычный ZIP? MS>Во-первых, так и делается. Во-вторых, объем объектов в среднем — 300-500 байт, зипу там просто негде "разогнаться".
Зачем жать по одному объекту? Надо архивировать весь архив! Если есть vector<string> то надо не по одной строке архивировать, а весь вектор.
Хотя можно поподробнее, что ты хочешь реализовать? У меня отражение полей на базу, а у тебя? Рекомендую хорошую книгу по ODMG "Обработка объектных баз данных в С++" Дэвида Джордана.
"Man feed machine
Machine feed man"
Peter Gabriel — OVO — The Tower That Ate People
Здравствуйте, adontz, Вы писали:
A>Зачем жать по одному объекту? Надо архивировать весь архив! Если есть vector<string> то надо не по одной строке архивировать, а весь вектор.
Всегда, когда это возможно — именно так надо делать. Но не всегда получается. Типичный случай — некая большая таблица в Metakit с миллионами сериализованных записей и произвольным доступом по индексу. Второй пример — та же таблица в Oracle. Как-то я не очень представляю себе процесс запаковки группы записей на сервере и передачу данных в виде block fetch. Короче говоря, весьма часты случаи, когда объект в 300-400 байт — это весь архив и есть. Но этих "архивов" — ну очень много.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Универсальное A>Возможности применения к классам без их изменения.
Ага, теперь понятно, почему ты хотел сериализовать по умолчанию все поля, за исключением "unserializable". Я бы к этому не сильно стремился — слишком уж много там граблей. А если при этом много legacy-кода с полиморфизмом, да еще и множественным наследованием — начинаются такие дебри и грабли...
Года 3 назад я сталкивался с подобной сериализацией (отягощенной версионностью), там было штук 30 такросов на разные случаи жизни — кошмар. Самый главный кошмар был — с полиморфными объектами и хитрой фабрикой классов. В общем, перехитрили сами себя.
К тому же, при грамотном проектировании, объектов, подлежащих сериализации получается не так уж и много, либо они все однотипны.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, McSeem2, Вы писали:
MS>Всегда, когда это возможно — именно так надо делать. Но не всегда получается. Типичный случай — некая большая таблица в Metakit с миллионами сериализованных записей и произвольным доступом по индексу. Второй пример — та же таблица в Oracle. Как-то я не очень представляю себе процесс запаковки группы записей на сервере и передачу данных в виде block fetch. Короче говоря, весьма часты случаи, когда объект в 300-400 байт — это весь архив и есть. Но этих "архивов" — ну очень много.
OK, ясно. Но понимаешь ли в чём дело. Если данных столько, что их запихали в Oracle, то оверхед в 20-30% по объёму ИМХО не трагедия.