LINUX.ORG.RU

Kaitai Struct 0.5

 , , ,


8

5

После трёх месяцев разработки состоялся релиз Kaitai Struct 0.5 — языка описания форматов структур данных. Идея проекта состоит в том, что описав структуру формата файла или сетевого протокола единожды на формальном языке .ksy, можно скомплировать такое описание в исходный код парсера на любом поддерживаемом языке программирования.

Список нововведений внушительный, самые заметные из них:

  • полная поддержка C++/STL;
  • поддержка новых целевых языков PHP7 (благодаря ProtoH) и Perl;
  • генерация GraphViz-диаграмм для форматов (ранние примеры демонстрировались в галерее);
  • новые возможности языка: switch-подобная конструкция для типов (чтобы не писать много условий), атрибут doc (для генерации документации в комментариях на целевом языке), цикл repeat-until, поддержка булевых типов, поддержка операций с объектом потока из языка выражений (_io.eof, _io.size, _io.pos);
  • существенное улучшение строгости парсинга .ksy компилятором, понятные сообщения об ошибках;
  • работа консольного визуализатора на Windows.

Семейство инструментов, поддерживающих Kaitai Struct, пополнилось:

Как всегда, доступна онлайн-версия на JavaScript, в которой можно поэкспериментировать с компилятором без установки.

>>> Подробности

Ответ на: комментарий от GreyCat

Вы же сначала ответили так, будто в курсе, что такое парсер-комбинаторы и эрланг. Зачем Вам теперь примеры и пояснения?

Если начать с простого, то эрланговский матчинг бинарей и парсером не является: он просто матчит биты, байты и строки без всякого бэктрекинга, ну и комбинаторов там нет в помине.

GoodRiddance ()
Ответ на: комментарий от GreyCat

Но почему-то там до сих пор болтается вручную написанный разбиратель пакета на чистом C++. Императивный, разумеется.

А какие, кстати, у императивных разбирателей форматов недостатки? Громоздкость кода, непрозрачность, что-то ещё? Ну и ещё сравнение по быстродействию интересно.

hobbit ★★★★★ ()
Ответ на: комментарий от anonymous

Где-то треть японских форматов отвалится, либо придётся приделывать внешние кодировки.

Если б только они. Поэтому я и не могу серьезно рассматривать отказ от кодировок.

GreyCat ★★ ()
Ответ на: комментарий от anonymous

В целом, можно переписать лучше, вам нужны PR?

Разумеется :)

GreyCat ★★ ()
Ответ на: комментарий от GoodRiddance

парсером не является: он просто матчит биты, байты и строки без всякого бэктрекинга

Что-то я не припомню, когда у нас в понятие «парсер» обязательно стал входить бэктрекинг.

комбинаторов там нет в помине.

Только вот почему-то 100% проектов по парсингу бинарных файлов на эрланге, которые я видел, именно ими по сути активно пользовались.

GreyCat ★★ ()
Ответ на: комментарий от GreyCat

Каких ещё проектов на эрланге?! Разбор бинарных структур входит в сам язык. Он происходит с помощью match-паттернов, которые комбинаторами не являются (т.к. их нельзя применить один к другому и получить третий).

GoodRiddance ()
Ответ на: комментарий от hobbit

А какие, кстати, у императивных разбирателей форматов недостатки? Громоздкость кода, непрозрачность, что-то ещё?

В первую очередь - непрозрачность. Провести преобразование спецификация => алгоритм - тривиально, это и машина может. А вот алгоритм => спецификация - это задача не самая простая. Появляется понятие состояния, его надо все время держать в голове. Когда число сущностей начинает достигать десятка - жить с таким становится сложно и люди начинают все равно писать некую «документацию по формату» в совершенно произвольном виде, чем невольно таки приходят к спецификации, но неформальной.

А из непрозрачности проистекает все остальное. Отлаживать и диагностировать сложно. О какой-то кросс-язычности (а зачастую и кросс-платформенности) можно забыть или по крайней мере понимать, что цена этого - сделать все в 2-3-4 экземплярах. Зачастую там, где автоматом можно было бы сделать эффективнее - не делается. Там, где можно было бы посмотреть и отладить сначала на основе какого-нибудь простенького скриптового Python / Ruby - приходится bite the bullet и делать все сразу по хардкору на C++, судорожно собирая убежавшие указатели и ловя segfault'ы и leak'и.

Идет время, возникают новые платформы и языки. Scala, Go, Rust, Elixir, Swift, Julia, Hack. Что происходит с императивными алгоритмами? Их придется переписать заново - зачастую потратив кучу времени на интимное общение с размерами указателей и особенностями паддинга на старой платформе.

Ну и ещё сравнение по быстродействию интересно.

Не очень корректно вопрос поставлен. Мы же не «функциональное vs императивное» сравниваем здесь. Декларативный - это значит, что есть какой-то более-менее устойчивый документ-спецификация, на основе которой производится разбор. Разбор может проводить интерпретатор спецификации - и тогда это будет потенциально медленно, либо спецификацию можно скомпилировать - и тогда это будет по сути ровно тот же императивный код, который бы был написан вручную. Разница между «скомпилированным императивным vs написанным вручную императивным» упирается

GreyCat ★★ ()
Ответ на: комментарий от Svoloch

Идея в том, что мне зачастую важнее первый этап - посмотреть глазками, поскольку в моих задачах формат зачастую неизвестен. Т.е. в код-то я добавить могу, но редактор этого не увидит. Попробую переформулировать: хотелось бы возможность определить что-то типа .toString() для каждого типа, который будет виден в редакторе. Причем язык на котором будет .toString() не так принципиален.

Вообще интересная мысль. Сейчас есть webide, которую активно пилит Tamás Koczka. Попробуйте, может, ему предложить - можно либо issue в проекте создать, либо даже проще - заходите на наш канал - обсудим?

GreyCat ★★ ()
Ответ на: комментарий от SZT

Попробую конкретизировать. Допустим, используется метод цепочек для решения коллизий т.е. файлы, имена которых дают одинаковый хеш, висят односвязным списком в памяти. Допустим, хеш-функция реализована на языке Си, ей мы подаем на вход имя файла, она возвращает хеш. Теперь, зная хеш, если у нас есть есть коллизии, надо перебирать все файлы в том односвязном списке. Получится ли через KS реализовать односвязный список? Или код для «движения» по списку тоже надо на Си писать?

SZT ★★★★ ()
Ответ на: комментарий от GreyCat

Что происходит с императивными алгоритмами? Их придется переписать заново - зачастую потратив кучу времени на интимное общение с размерами указателей и особенностями паддинга на старой платформе.

Можно сделать некий Си-подобный DSL, который бы был легко транслируемым под все эти новомодные языки. Вот например язык Haxe в кучу всего можно оттранслировать

SZT ★★★★ ()
Ответ на: комментарий от GoodRiddance

unpack в Perl/Python/Ruby/PHP тоже «входит в сам язык». Но мы же сейчас не про него, а про какие-то более сложные конструкции с его использованием?

Речь о штуках вроде https://github.com/ScrimpyCat/BMFontEx/blob/master/lib/bmfont/binary.ex - ну, или, если именно на самом эрланге - https://github.com/tim/pardec/blob/master/src/pardec.erl - и там, разумеется, весь смысл именно в их комбинировании.

GreyCat ★★ ()
Ответ на: комментарий от GreyCat

stdint.h - это C99

Да, а в C++ это завезли в 11-м. И, кстати, пользуйтесь тогда уж cstdint.

А какие там линуксовые хедеры?

sys/types.h, endian.h, byteswap.h

anonymous ()
Ответ на: комментарий от GreyCat

далеко не во всех языках есть аналог типа Date / Time.

double в том или ином виде есть практически везде

DateTime практически в большинстве языков имплементируется как double число дней начиная с некой нулевой даты, если что

anonymous ()
Ответ на: комментарий от GreyCat

Речь о штуках

Вообще-то эту речь начал я, и я, наверно, в курсе, о чём она. А именно, о вещах, встроенных в язык. Например:

https://github.com/erlang/otp/blob/maint/lib/diameter/src/base/diameter_codec...

Есть подозрение, что этот инструмент в общем помощнее, т.к. тесно интегрируется в произвольный код. Плюс отдельные биты можно вытаскивать, не прибегая к маскам и прочим не слишком декларативным вещам.

GoodRiddance ()
Ответ на: комментарий от GreyCat

если говорить о С++98, чем auto_ptr не угодил?

anonymous ()
Ответ на: комментарий от SZT

Например, некая файловая система, в ней хеш-таблица, внутри хеш-таблицы у нас структура описания файлов (имя файла, адрес начала файла, размер файла), в хеш-таблице качестве ключа используется имя файла. Надо получить файл с таким-то именем.

Прямо на диске хэш-таблица? Таблица будет скорее всего иметь какие-то показатели количества и какой-то способ определить размер элемента. Зачитать ее всю поэлементно в память KS сможет (или - при желании - не всю, а on demand). Затем уже дело программиста, как эту таблицу использовать. Искать ли файл по имени или, не знаю там, на принтере распечатать и в рамку на стену повесить.

GreyCat ★★ ()
Ответ на: комментарий от SZT

KS не очень работает с памятью, в частности, с указателями и всем таким. Если считать, что это все в потоке и указатели односвязного списка - указателями на байты внутри потока - то, разумеется, сможет. Собственно, так работает туча всяких самовложенных форматов типа RIFF или TIFF с его IDF0.

GreyCat ★★ ()
Ответ на: комментарий от GreyCat

Прямо на диске хэш-таблица? Таблица будет скорее всего иметь какие-то показатели количества и какой-то способ определить размер элемента.

Да, на диске в сериализованном виде хранится хеш-таблица. Записи в хеш-таблице будут иметь допустим такой вид:

used bytes | text description          | d
-----------+---------------------------+---------------
somewhere  | ptr_to_first_file_ds = 8  | указатель на первый файл в связном списке
...
8..11      | ASCIIZ file_1 name "aaa"  |\
12..15     | uint32_t file_1_start = 0 | > struct file 
16..19     | uint32_t file_1_len   = 10|/
20..23     | uint32_t ptr_to_next  = 40|
...
40..43     | ASCIIZ file_2 name "bbb"  |\
44..47     | uint32_t file_2_start = 11| > struct file
48..51     | uint32_t file_2_len   = 7 |/
20..23     | uint32_t ptr_to_next = 0xffffffff // конец
Хотим найти файл с именем «bbb» - пропускаем это имя через хеш-функцию - хеш это индекс массива somewhere, получаем получаем указатель на первый элемент связного списка, там файл aaa. И надо пройтись по всему этому связному списку, и остановиться, когда найдем файл bbb или когда дойдем до конца связного списка, а конец связного списка когда ptr_to_next = 0xffffffff - значит файл не найден

SZT ★★★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от anonymous

Да, а в C++ это завезли в 11-м.

Если говорить про практический результат - фактически везде, кроме MSVC, это есть как минимум с начала 2000-х. В MSVC есть с 2010, до этого вопрос решается подкладыванием одного файлика.

И, кстати, пользуйтесь тогда уж cstdint.

С ним по хорошему надо писать std::int32_t, что делать совершенно не хочется.

sys/types.h, endian.h, byteswap.h

Ну, как минимум это не линуксовые, а вполне себе вещи, стандартизированные POSIX/Open Group. На MSVC они, насколько я понимаю, тоже есть эдак с ~2008, если не раньше.

Но по хорошему, конечно, надо бы нам CI на Windows-машине пытаться собирать и прогонять C++-тесты.

GreyCat ★★ ()

Вы «украли» мою идею. На самом деле, конечно, нет — понятно, что разным людям одно и то же в голову приходит. Просто некоторые доходят до реализации, некоторые нет.

Короче, хорошую штуку делаете. Если не секрет, сколько у Вас в команде человек? И планируете ли как-то пытаться окупаться/за счёт чего-то существовать — или это чисто «считаю такую штуку полезной => буду делать»?

sasha1024 ()
Ответ на: комментарий от GoodRiddance

В чем тогда ваш посыл? В том, что в эрланге есть unpack? Ну, есть. И в почти любых других языках тоже есть.

Есть подозрение, что этот инструмент в общем помощнее

В том, что эрланговский аналог unpack мощнее питоновского или там перлового сам по себе? Честно говоря, сомневаюсь.

В том, что отдельный unpack мощнее, чем KS? Это как-то глупо сравнивать.

В том, что на тюринг-полном эрланге можно написать произвольный алгоритм? Можно, никто не спорит. На любом другом языке общего назначения тоже можно.

Что с чем хочется сравнить-то?

GreyCat ★★ ()
Ответ на: комментарий от SZT

в общем, если надо из такой файловой системы извлечь файл с конкретным именем на нескольких языках, под которые умеет кодогенерировать KS, надо для каждого языка ручками писать логику: «посчитать hash(bbb), из него получить адрес первого элемента связного списка (если адрес первого элемента 0xffffffff то нет такого файла), перебирать, пока не встретим bbb в имени файла или пока связный список не кончится, если нашли файл то вот его адрес начала и размер в байтах», верно?

SZT ★★★★ ()
Ответ на: комментарий от GreyCat

Разница между «скомпилированным императивным vs написанным вручную императивным» упирается...

Ну вот, на самом интересном месте!

Но впрочем, из предыдущего предложения я понял - мысль сводилась к тому, что теоретически разницы по быстродействию быть не должно.

hobbit ★★★★★ ()
Ответ на: комментарий от sasha1024

Вы «украли» мою идею.

Знали бы вы, сколько народа мне это уже говорило ;)

Короче, хорошую штуку делаете.

Спасибо :) Не хотите делать хорошую штуку вместе? Интересных задач вагон еще.

Если не секрет, сколько у Вас в команде человек?

Это очень расплывчатое понятие. У нас нет формальной организации, каких-то регулярных сходок, и тем более офиса с зарплатой. Что-либо контрибьютили пока всего человек 30 (если по всем подпроектам), весомый вклад - наверное, у человек 5-6.

И планируете ли как-то пытаться окупаться/за счёт чего-то существовать

По крайней мере пока - не планируем.

GreyCat ★★ ()
Ответ на: комментарий от hobbit

Да, прошу прощения, убился кусок при отправке, видимо. Смысл был в том, что в теории разницы особенно не будет, на практике - разница будет за счет того, что «ручная» версия будет куда более «дырявая» за счет отсутствия огромной кучи всяких проверок и обработок исключений, которые по идее надо делать, но на которые тратится время в runtime.

В ручной версии есть еще соблазн сразу делать какие-то преобразования и раскладывать в памяти не совсем то же самое, что лежит на диске, чем тоже иногда можно выиграть по быстродействию.

GreyCat ★★ ()
Ответ на: комментарий от SZT

(если адрес первого элемента 0xffffffff то нет такого файла)

Вот это можно (и имеет смысл) реализовать на KS - т.е. либо мы получаем запись, либо null (или какой-то аналог).

А так - во всем остальном - да, верно.

GreyCat ★★ ()

Смотрю документацию и вижу

KS works always with seekable streams

TCP-сокеты, пайпы и прочие потоковые вещи возможны/планируются?

anonymous ()
Ответ на: комментарий от GreyCat

А есть ли в планах встроить некий язык в KS (он очевидно будет полным по Тьюрингу) на котором можно было б эту логику реализовать один раз, чтобы она могла быть оттранслинована во все поддерживаемые языки, чтобы на выходе получить некую функцию getfile(descriptor,«filename») которая б возвращала адрес начала файла и его размер в байтах?

SZT ★★★★ ()
Ответ на: комментарий от GreyCat

Прошу прощения, мне следовало с самого начала сопроводить код развернутым пояснением, а не заставлять читателя разгадывать по коду, что же я пытался донести.

Код призван проиллюстрировать, как обойтись без копирования строк и блобов. Всё остальное в нем максимально упрощено.

Самое существенное и вопиющее упрощение — это использование vector вместо списков со stack-based memory allocation / arena.

Отказаться от парсинга из istream.

Да, zero-copy на istream не натянуть никак. Толку от «потоковости» в любом случае мало из-за того, что требуется поддерживать seek.

Вместо этого парсинг идет из некоей самодельной структуры buffer_view_t, которая есть просто указатель + длина.

Эта структура — имитация std::string_view / boost::iterator_range , самодельной я её сделал в целях наглядности, чтобы у читателя не могло возникнуть ощущения о какой-то зашитой в библиотеки магии. Поля структуры совпадают с аргументами конструктора std::string_view.

Принципиально, что эта структура фигурирует на выходе парсера. А на вход парсера можно подавать ссылку на std::vector<char>, std::string, или любой подобный контейнер, поскольку из них легко сделать тот самый buffer_view_t aka std::string_view / boost::iterator_range .

Отказаться от std::string (и забить, по крайней мере пока, на кодировки) - использовать buffer_view_t и для строчек, и для массивов байт. Честно говоря, пока все равно не понятно - зачем? std::string по сути - то же самое. При желании можно у него двигать внутренние указатели по массиву байт.

Вот ради этого весь пример и затеян. Разница между buffer_view_t и std::string в том, что std::string выделяет новый кусок памяти в heap (это относительно дорогая операция) и копирует в этот кусок все символы строки. А buffer_view_t ничего не выделяет и ничего не копирует, он вместо этого ссылается на внешнюю по отношению к нему память.

Перейти от парадигмы «класс включает методы, чтобы парсить себя» к «есть куча статических методов parse, которые имеют на входе buffer_view_t, а на выходе - запрошенный struct + обновленный buffer_view_t».

Желательно скрыть детали парсинга от пользовательского кода. Поэтому в классах, описывающих результат парсинга, «методы чтобы парсить себя» нежелательны. Как именно осуществить сокрытие - дело второе и не слишком принципиальное; в варианте со статическими функциями парсинга, эти функции должны быть размещены не в заголовочном файле, в а cpp-шнике, внутри anonymous namespace [и поэтому я не потрудился написать при них слово inline]. Интерфейс функций парсинга выбран абы какой, поскольку я на данный момент не понимаю, какой на самом деле нужен интерфейс для полноценного kaitai-парсера.

Отказаться от exceptions и решать ошибочные ситуации через assert.

Это упрощение, чтобы писать поменьше букв. Раз уж заговорили об исключениях, их не следует использовать для обработки штатных ситуаций парсинга, поскольку операция throw дорогая. А вот как замену assert-ам для уведомления пользователя о полном провале парсинга — самое то.

Использовать extended initializer lists, что C++11, но, по идее, это можно обойти через явные временные переменные.

Это просто чтобы было меньше букв: поленился писать конструкторы для структур...

Manhunt ★★★★★ ()
Ответ на: комментарий от anonymous

строки могут быть и в том и в том формате (не будь намешано, можно было бы mojibake в качестве ключей и использовать)

А не должно это обрабатываться где-то уровнем выше, примерно там же, где и хэш-таблицы, и прочие нетривиальные особенности / извраты конкретных форматов? Всё-таки *бинарный* формат, предполагающий на этапе парсинга сопоставление строк с учётом сематники кодировок или там unicode normalization, это нечто весьма странное.

Manhunt ★★★★★ ()
Ответ на: комментарий от hobbit

А какие, кстати, у императивных разбирателей форматов недостатки?

error-prone

Manhunt ★★★★★ ()

А как в плюсах строки представляете? С национальными символами?

Xintrea ★★★★★ ()
Ответ на: комментарий от anonymous

TCP-сокеты, пайпы и прочие потоковые вещи возможны/планируются?

Возможны через предварительное чтение того куска, который планируется разобрать, в память и парсингом из памяти.

GreyCat ★★ ()
Ответ на: комментарий от SZT

Это будет означать придумать некий язык, транслируемый во все поддерживаемые. Уже есть Haxe, зачем делать плохой клон этого в KS?

GreyCat ★★ ()
Ответ на: комментарий от Manhunt

Всё-таки *бинарный* формат, предполагающий на этапе парсинга сопоставление строк с учётом сематники кодировок или там unicode normalization, это нечто весьма странное.

Кодировки - относительно прямолинейная задача. Не скажу, что простая, но по крайней мере с очень четко ограниченным набором параметров. Понятие «строк» есть в большинстве современных языков - хотим мы того или нет. Вполне логично обеспечить несложный дополнительный сервис по декодированию массива байт в строку. Ну и, наконец, к сожалению, да, есть ряд странных форматов, где это важно (или по крайней мере сильно упрощает жизнь) именно на этапе парсинга: когда в одном месте литерал записан, как 40 41 42, а в другом - 40 00 41 00 42 00.

GreyCat ★★ ()

Неплохо бы скриншотов (или даже скринкастов) для гуёвин.

frob ★★★★★ ()
Ответ на: комментарий от Manhunt

Спасибо, теперь понятнее. Чем-то мне даже начинает нравится этот подход - в том числе тем, что это реально на C реализовать.

Принципиально, что эта структура фигурирует на выходе парсера.

Я пока на самом деле не понял, зачем ее столько раз копировать и чем парадигма потоков с хранением состояния «мы на таком-то байте сейчас» хуже. В худшем случае - можно ведь просто модифицировать buffer_view_t? Он же нигде не переиспользуется, насколько я вижу?

Или тут идея в том, что buffer_view_t очень маленький и его реально возвращать через пару регистров?

GreyCat ★★ ()
Ответ на: комментарий от GreyCat

У Haxe другая область применения, он слишком высокоуровневый, для такой задачи нужно делать не клон Haxe а какой-то адаптированный лиспо-си, на котором было бы легче разбирать всякие бинарные структуры, работать на уровне отдельных битов. Например, чтобы указатель может указывать даже на конкретный бит в битовом потоке, чтобы например можно было легко прочитать непрерывный кусок битов, который частично пересекает два байта. Еще MSB-LSB битовые указатели отдельно сделать. Сами типы можно реализовать как массивчики битов, к которым цепляем описания, на основании которых функции могут что-то там с ними осмысленное делать

Кроме того, реализовать встроенные функции разворота из big-little endian, MSB-LSB. Скажем, тип bit8_t в таком теоретическим языке это будет как массив из 8 бит, и если мы например хотим сложить два bit8_t и результат записать в bit9_t, интерпретируя первый bit8_t как MSB а второй как LSB, результат же записать в bit9_t который будет LSB то надо записать нечто вроде такого

(declare a (len 8) unsigned MSB)
(declare b (len 8) unsigned LSB)
(LOAD a 10)
(LOAD b 20)
(declare out (len 9) unsigned LSB)
(ADD out a b) // первый аргумент - туда пишет результат
ADD анализирует типы a, b, out и на основе этого делает сложение с учетом этих особенностей т.е. значение в a трактуется как MSB и значение b и out как LSB. Можно даже так:
(ADD (CAST a LSB) b out)
и тогда сложение отработает таким образом, будто все три типа LSB. Что-то похожее можно сделать для big-little endian, one's complement/two's complement и других возможных схем кодирования signed значений https://en.wikipedia.org/wiki/Signed_number_representations , и делать что-то такое:
(declare a (len 8) signed MSB twos_compl)
(declare b (len 8) signed LSB ones_compl)
(LOAD a -13)
(LOAD b -40)
(declare out (len 9) signed LSB ones_compl)
(ADD out a b)

SZT ★★★★ ()
Ответ на: комментарий от frob

Неплохо бы скриншотов (или даже скринкастов) для гуёвин.

GreyCat ★★ ()
Ответ на: комментарий от GreyCat

Спасибо. Интерпретатор выглядит занятно. Пора потыкать палочкой... =)

frob ★★★★★ ()
Ответ на: комментарий от frob

На самом деле так кажется, потому что там анимированная гифка, да ;) Интерпретатор, сам по себе, субъективно, один из самых спорных среди этих проектов - это по сути полноценная альтернативная реализация и попытка «переписать все еще раз с нуля». Сильно не уверен, что автору хватит сил.

Самый перспективный, по-моему, это Web IDE. Там автор очень активен и доделывает что-то практически каждый день.

GreyCat ★★ ()
Ответ на: комментарий от GreyCat

Или тут идея в том, что buffer_view_t очень маленький и его реально возвращать через пару регистров?

Я надеюсь, что компилятор все эти вызовы parse() заинлайнит друг в друга и как следует оптимизирует. Вот результат компиляции (ко вспомогательным parse дописано слово static, затем выполнено g++ -std=c++11 -O2 -S c.cpp -o - | c++filt), главный цикл выделен жирным:


.file «c.cpp»
.section .rodata.str1.1,«aMS»,@progbits,1
.LC0:
.string «vector::_M_default_append»
.section .text._ZNSt6vectorI6file_tSaIS0_EE17_M_default_appendEm,«axG»,@progbits,std::vector<file_t, std::allocator<file_t> >::_M_default_append(unsigned long),comdat
.align 2
.p2align 4,,15
.weak std::vector<file_t, std::allocator<file_t> >::_M_default_append(unsigned long)
.type std::vector<file_t, std::allocator<file_t> >::_M_default_append(unsigned long), @function
std::vector<file_t, std::allocator<file_t> >::_M_default_append(unsigned long):
.LFB688:
.cfi_startproc
pushq %r14
.cfi_def_cfa_offset 16
.cfi_offset 14, -16
testq %rsi, %rsi
pushq %r13
.cfi_def_cfa_offset 24
.cfi_offset 13, -24
pushq %r12
.cfi_def_cfa_offset 32
.cfi_offset 12, -32
pushq %rbp
.cfi_def_cfa_offset 40
.cfi_offset 6, -40
pushq %rbx
.cfi_def_cfa_offset 48
.cfi_offset 3, -48
movq %rsi, %rbx
je .L1
movq 8(%rdi), %rcx
movq 16(%rdi), %rax
movabsq $-6148914691236517205, %rdx
movq %rdi, %rbp
subq %rcx, %rax
sarq $3, %rax
imulq %rdx, %rax
cmpq %rax, %rsi
ja .L3
movq %rsi, %rdx
movq %rcx, %rax
.p2align 4,,10
.p2align 3
.L5:
movl $0, (%rax)
movq $0, 8(%rax)
addq $24, %rax
movq $0, -8(%rax)
subq $1, %rdx
jne .L5
leaq (%rbx,%rbx,2), %rax
leaq (%rcx,%rax,8), %rax
movq %rax, 8(%rbp)
.L1:
popq %rbx
.cfi_remember_state
.cfi_def_cfa_offset 40
popq %rbp
.cfi_def_cfa_offset 32
popq %r12
.cfi_def_cfa_offset 24
popq %r13
.cfi_def_cfa_offset 16
popq %r14
.cfi_def_cfa_offset 8
ret
.p2align 4,,10
.p2align 3
.L3:
.cfi_restore_state
movq (%rdi), %rdi
subq %rdi, %rcx
sarq $3, %rcx
imulq %rdx, %rcx
movabsq $768614336404564650, %rdx
movq %rdx, %rax
subq %rcx, %rax
cmpq %rax, %rsi
ja .L25
cmpq %rsi, %rcx
movq %rsi, %rax
movq $-16, %r12
cmovnb %rcx, %rax
addq %rcx, %rax
jnc .L26
.L7:
movq %r12, %rdi
call operator new(unsigned long)
movq 0(%rbp), %rdi
movq 8(%rbp), %rdx
movabsq $-6148914691236517205, %rcx
movq %rax, %r13
subq %rdi, %rdx
sarq $3, %rdx
imulq %rcx, %rdx
movq %rdx, %rcx
.L8:
leaq (%rcx,%rcx,2), %r14
salq $3, %r14
testq %rdx, %rdx
je .L10
movq %rdi, %rsi
movq %r14, %rdx
movq %r13, %rdi
call memmove
movq 0(%rbp), %rdi
.L10:
leaq 0(%r13,%r14), %rax
movq %rbx, %rcx
movq %rax, %rdx
.p2align 4,,10
.p2align 3
.L12:
movl $0, (%rdx)
movq $0, 8(%rdx)
addq $24, %rdx
movq $0, -8(%rdx)
subq $1, %rcx
jne .L12
leaq (%rbx,%rbx,2), %rdx
testq %rdi, %rdi
leaq (%rax,%rdx,8), %rbx
je .L13
call operator delete(void*)
.L13:
addq %r13, %r12
movq %r13, 0(%rbp)
movq %rbx, 8(%rbp)
movq %r12, 16(%rbp)
popq %rbx
.cfi_remember_state
.cfi_def_cfa_offset 40
popq %rbp
.cfi_def_cfa_offset 32
popq %r12
.cfi_def_cfa_offset 24
popq %r13
.cfi_def_cfa_offset 16
popq %r14
.cfi_def_cfa_offset 8
ret
.p2align 4,,10
.p2align 3
.L26:
.cfi_restore_state
cmpq %rdx, %rax
ja .L7
testq %rax, %rax
jne .L27
movq %rcx, %rdx
xorl %r12d, %r12d
xorl %r13d, %r13d
jmp .L8
.L25:
movl $.LC0, %edi
call std::__throw_length_error(char const*)
.L27:
imulq $24, %rax, %r12
jmp .L7
.cfi_endproc
.LFE688:
.size std::vector<file_t, std::allocator<file_t> >::_M_default_append(unsigned long), .-std::vector<file_t, std::allocator<file_t> >::_M_default_append(unsigned long)
.section .rodata.str1.1
.LC1:
.string «c.cpp»
.LC2:
.string «raw_data.count >= 4»
.LC3:
.string «raw_data.count >= resultCount»
.text
.p2align 4,,15
.globl parse(test_format_t&, buffer_view_t&)
.type parse(test_format_t&, buffer_view_t&), @function
parse(test_format_t&, buffer_view_t&):
.LFB679:
.cfi_startproc
pushq %r13
.cfi_def_cfa_offset 16
.cfi_offset 13, -16
pushq %r12
.cfi_def_cfa_offset 24
.cfi_offset 12, -24
pushq %rbp
.cfi_def_cfa_offset 32
.cfi_offset 6, -32
pushq %rbx
.cfi_def_cfa_offset 40
.cfi_offset 3, -40
subq $8, %rsp
.cfi_def_cfa_offset 48
movq 8(%rsi), %rbp
movq (%rsi), %rbx
testq %rbp, %rbp
je .L29
movq %rdi, %r12
movq 8(%rdi), %rcx
movabsq $-6148914691236517205, %r13
jmp .L34
.p2align 4,,10
.p2align 3
.L30:
jnb .L31
leaq (%rax,%rax,2), %rax
leaq (%rsi,%rax,8), %rcx
movq %rcx, 8(%r12)
.L31:
cmpq $3, %rbp
jbe .L42
movsbl 1(%rbx), %eax
movsbl (%rbx), %esi
leaq -4(%rbp), %rdx
addq $4, %rbx
sall $8, %eax
addl %eax, %esi
movsbl -2(%rbx), %eax
sall $16, %eax
addl %esi, %eax
movsbl -1(%rbx), %esi
sall $24, %esi
addl %esi, %eax
cmpq %rdx, %rax
movl %eax, -24(%rcx)
ja .L43
movq %rbx, -16(%rcx)
addq %rax, %rbx
subq %rax, %rdx
movq %rax, -8(%rcx)
movq %rdx, %rbp
je .L29
.L34:
movq (%r12), %rsi
movq %rcx, %rdx
subq %rsi, %rdx
sarq $3, %rdx
imulq %r13, %rdx
leaq 1(%rdx), %rax
cmpq %rdx, %rax
jbe .L30
movl $1, %esi
movq %r12, %rdi
call std::vector<file_t, std::allocator<file_t> >::_M_default_append(unsigned long)
movq 8(%r12), %rcx
jmp .L31

.p2align 4,,10
.p2align 3
.L29:
addq $8, %rsp
.cfi_remember_state
.cfi_def_cfa_offset 40
movq %rbx, %rax
xorl %edx, %edx
popq %rbx
.cfi_def_cfa_offset 32
popq %rbp
.cfi_def_cfa_offset 24
popq %r12
.cfi_def_cfa_offset 16
popq %r13
.cfi_def_cfa_offset 8
ret
.L42:
.cfi_restore_state
movl parse(unsigned int&, buffer_view_t const&)::__PRETTY_FUNCTION__, %ecx
movl $31, %edx
movl $.LC1, %esi
movl $.LC2, %edi
call __assert_fail
.L43:
movl parse(buffer_view_t&, buffer_view_t const&, unsigned long const&)::__PRETTY_FUNCTION__, %ecx
movl $18, %edx
movl $.LC1, %esi
movl $.LC3, %edi
call __assert_fail
.cfi_endproc
.LFE679:
.size parse(test_format_t&, buffer_view_t&), .-parse(test_format_t&, buffer_view_t&)
.section .rodata
.align 32
.type parse(buffer_view_t&, buffer_view_t const&, unsigned long const&)::__PRETTY_FUNCTION__, @object
.size parse(buffer_view_t&, buffer_view_t const&, unsigned long const&)::__PRETTY_FUNCTION__, 73
parse(buffer_view_t&, buffer_view_t const&, unsigned long const&)::__PRETTY_FUNCTION__:
.string «buffer_view_t parse(buffer_view_t&, const buffer_view_t&, const size_t&)»
.align 32
.type parse(unsigned int&, buffer_view_t const&)::__PRETTY_FUNCTION__, @object
.size parse(unsigned int&, buffer_view_t const&)::__PRETTY_FUNCTION__, 49
parse(unsigned int&, buffer_view_t const&)::__PRETTY_FUNCTION__:
.string «buffer_view_t parse(u4_t&, const buffer_view_t&)»
.ident «GCC: (SUSE Linux) 4.8.5»
.section .note.GNU-stack,"",@progbits



Не то, чтобы супер, но от копирования buffer_view_t не осталось и намёка.

Manhunt ★★★★★ ()
Ответ на: комментарий от GreyCat

Мне просто представляется, что что-то такое как интерпретатор или гуевозилка наподобие той, что пытались сделать в DataWorkshop наиболее подходит для случая «вот вам неведомое нечто, разберитесь что это такое».

frob ★★★★★ ()

Нужно!

Но, нужно именно в первую очередь как язык описания, не особо привязаный к реализации

anonymous ()
Ответ на: комментарий от GreyCat

Знали бы вы, сколько народа мне это уже говорило ;)

Ну, так это хорошо. Если идея приходит в головы многим людям, значит время её пришло. Что она востребована.

Спасибо :) Не хотите делать хорошую штуку вместе? Интересных задач вагон еще.

К сожалению, нет. Если бы платили — то может быть. А так, у меня идей куча (в т.ч. есть те, которые я считаю даже более важными), и если делать за свой счёт, то я бы сосредоточился на другом. Хотя, может быть, пути пересекутся и что-то и закомиттю.

По крайней мере пока - не планируем.

Ясно. Ну у меня, по-моему, так же; большинство приходящих в голову идей в стиле «вот это было бы полезно / так было бы лучше» (только я редко довожу до конца). А не «вот на этом можно было бы сделать денег так-то» — для этого отдельный талант нужно иметь.

sasha1024 ()
Ответ на: комментарий от anonymous

Если я все правильно понял, в рамках предлагаемого подхода нельзя дать полного исчерпывающего описания произвольного формата т.к. в формате могут быть сериализованы разные нетривиальные структуры данных, например хеш-таблицы, двоичные деревья и прочее, а предлагаемый язык описания не позволяет это все описывать. Но может быть это и не надо

SZT ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.