Название: чтение и запись битовых структур данных Отправлено: kambala от Апрель 23, 2021, 23:40 Есть некоторый бинарный формат, в котором данные имеют размер в битах. Синтетический пример: (тип int взят от балды)
Код и так далее. Причем размер не всех полей известен на момент компиляции. Только точно известно, что не бывает полей шире, чем 64 бита. 1) Есть какие-то готовые библиотеки, которые смогут буфер с байтами превратить в заданные структуры? (ну и обратный процесс) 2) как описать эти структуры данных? Хочется чего-то более проверяемого на момент компиляции, чем обычный сишный bitfield. Какие трюки можно использовать на шаблонах/трейтах/концептах? Наверное, в идеале хотелось бы, чтобы правильный тип полю назначался в зависимости от заданной битовой ширины, что-то типа такого: Код
низкоуровневый код чтения битов с помощью сдвигов чисел у меня есть, интересует что-то более высокоуровневое. Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Апрель 24, 2021, 07:13 Не слышал о таких либах. Если велик-вариант интересен, то
Если "размер не всех полей известен на момент компиляции", то отделаться bitfield все равно не удастся. Я бы хранил в памяти "нормальные" члены класса (int, short, char), и нормальные вектора (если это не противоречит др требованиям). А для чтения/записи в биты нужно иметь таблицы битовых размеров, возможно мапа с ключом typeof() Название: Re: чтение и запись битовых структур данных Отправлено: Old от Апрель 24, 2021, 07:54 Причем размер не всех полей известен на момент компиляции. Только точно известно, что не бывает полей шире, чем 64 бита. Т.е. в формате вместе со значением поля указывается и его размер в битах?Или вы имеете ввиду, что пользователь этого формата должен иметь возможность выбирать любой размер поля от 1-64 бита? https://github.com/CrustyAuklet/bitpacker https://github.com/wkaras/C-plus-plus-library-bit-fields Название: Re: чтение и запись битовых структур данных Отправлено: Old от Апрель 24, 2021, 11:41 А вообще тема конечно обширная. Все зависит от того, что вы хотите: если вам нужны только pack/unpack - это будет одно решение. Если вы хотите хранить такие структуры в памяти и работать с ними из бизнес-логики, то другое.
Для примера: Код
Название: Re: чтение и запись битовых структур данных Отправлено: AkonResumed от Апрель 24, 2021, 15:58 В плане использования на уровне бизнес-логики - просто наложить placement new:
Код: // Packed data Это я привел вариант для чтения (распаковки) данных. Для записи (упаковки) - абсолютно тоже самое, только в другую сторону. Да, и здесь класс бизнес логики предполагает время жизни буфера большим своего. Короче, этот класс - интерпретатор, создаваемый по месту. Ну как бы не совсем бизнес-логика, а скорее хелпер. Название: Re: чтение и запись битовых структур данных Отправлено: Racheengel от Апрель 26, 2021, 14:09 MessagePack?
https://msgpack.org/ Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Апрель 26, 2021, 19:30 спасибо! отвечу по порядку.
Не слышал о таких либах. Если велик-вариант интересен, то велик интересен, если ничего пригодного не найдется :)Если "размер не всех полей известен на момент компиляции", то отделаться bitfield все равно не удастся. Я бы хранил в памяти "нормальные" члены класса (int, short, char), и нормальные вектора (если это не противоречит др требованиям). А для чтения/записи в биты нужно иметь таблицы битовых размеров, возможно мапа с ключом typeof() таблицы битовых размеров есть, некоторые из них во внешних файлах и могут меняться с течением времени, также у разных источников данных могут быть разные размеры. те, что известны на момент компиляции, фиксированы. как хранить "нормальные" члены класса не очень понял, ведь точно известно только то, что значение уместится в int64. Причем размер не всех полей известен на момент компиляции. Только точно известно, что не бывает полей шире, чем 64 бита. Т.е. в формате вместе со значением поля указывается и его размер в битах?Или вы имеете ввиду, что пользователь этого формата должен иметь возможность выбирать любой размер поля от 1-64 бита? https://github.com/CrustyAuklet/bitpacker https://github.com/wkaras/C-plus-plus-library-bit-fields вторая ссылка: открыл пдф документацию и... ничего не понял :) файл с тестами тоже понимания особого не принес. также в единственном issue пишут, что Цитировать G++ uses more than 3GB of memory (I estimated 6, although I couldn't be sure as the memory monitor stopped working the moment thrashing started). CLang++ only uses up to 1.4 GB of memory although it can take 3-5 minutes too and use up one core fully (ensure you have proper cooling). что как-то не особо приятно.первая ссылка: вот тут вменяемая документация :) даже удалось тестовый код написать. но там неприятная штука есть: Цитировать little endian byte order not yet implemented for packing/unpacking (yet...) у меня данные как раз в little endian. для «обычных» чисел можно выкрутиться простым переворотом байт, а вот с битами оказалось чуть сложнее...пример существующего кода, который «просто работает» (случай big endian архитектур не берем): Код получить то же самое на этой либе получилось лишь с помощью переворота всех битов в буфере и с последующим чтением с LSB: Код придется или ждать пока автор допилит поддержку LE (хотя уже год не было коммитов, только в другой ветке, но там другая тема) или самому ее добавлять (для начала разобрать этот супершаблонный код) или писать велик с блэкджеком и шлюхами :) для полей неизвестной ширины надо будет пользоваться функциями get / store (а может и известные тоже проще через эти функции), т.к. все равно надо будет делать обертки для порядка полей / автоматического сдвига счетчика. А вообще тема конечно обширная. Все зависит от того, что вы хотите: если вам нужны только pack/unpack - это будет одно решение. Если вы хотите хранить такие структуры в памяти и работать с ними из бизнес-логики, то другое. думаю, что лучше иметь сырые битовые данные в одних структурах («сырых»), которые и будут читаться/писаться из/в файл, а бизнес-логику на других, более понятных структурах, которые будут конвертироваться из/в «сырые» структуры.В плане использования на уровне бизнес-логики - просто наложить placement new: мне этот вариант не нравится тем, что в большинстве случаев я не могу работать с сырыми данными напрямую — их надо преобразовывать в более понятные пользователю (и коду) вещи.Это я привел вариант для чтения (распаковки) данных. Для записи (упаковки) - абсолютно тоже самое, только в другую сторону. Да, и здесь класс бизнес логики предполагает время жизни буфера большим своего. Короче, этот класс - интерпретатор, создаваемый по месту. Ну как бы не совсем бизнес-логика, а скорее хелпер. MessagePack? насколько я понял, это что-то типа протобафа. такое не подходит, потому что у меня известная жесткая внутренняя структура (файла) — надо именно с таким бинарным форматом и работать.https://msgpack.org/ сделал еще небольшую попытку повелосипедить (до того, как начал смотреть те библиотеки). Код работает, но мне кажется можно как-то получше :) потом еще заметил, что в BitPacker тот же трюк используется: Код
P.S. вопрос знатокам :) как задать массив (обычный или std::array) из std::byte по-человечески? у меня получается только с явным вызовом конструктора для каждого элемента как в коде выше. ([unsigned] char предлагать не надо :) ) Код
Название: Re: чтение и запись битовых структур данных Отправлено: juvf от Апрель 27, 2021, 06:53 1) Есть какие-то готовые библиотеки, которые смогут буфер с байтами превратить в заданные структуры? (ну и обратный процесс) Я делаю через юнионКод: struct LCanOpen При получении данных я не распихиваю каждый битик сдвигами в нужное поле, а сразу весь буфер помещаю в data Код: uint64_t recData; Код: unsigned int x = bjm.x; зы только сейчас заметил "Причем размер не всех полей известен на момент компиляции". Мой вариант тут наверно не подойдет. Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Апрель 27, 2021, 08:35 как хранить "нормальные" члены класса не очень понял, ведь точно известно только то, что значение уместится в int64. "Нормальные" имелось ввиду что все песни с битами только для I/O, а так нормальные структуры. Пока неясно нужно ли битовое представление в памяти. Даже если "иногда нужно" то может проще использовать ф-ции I/O на лету, расходы невелики. Уточните этот момент чтобы не гонять воздух.Если "только I/O" то надо заряжать какой-то CBitStream и операторы << и >> для каждой структуры, собсно это все. велик интересен, если ничего пригодного не найдется "Готовые проверенные" хороши для типовых, хорошо изученных задач. Отсюда частенько делается вывод что, мол, для всего , и "все уже давно написано" :) Но стоит задаче быть просто "не такой уж популярной" - и число "готового" резко падает, а с "проверенным" проблемы. Напр здесь найденное особого впечатления не производит, хотя возможно и пригодно.Название: Re: чтение и запись битовых структур данных Отправлено: Old от Апрель 27, 2021, 08:47 Отсюда частенько делается вывод что, мол, для всего , и "все уже давно написано" :) Вы уже много лет делаете этот ошибочный вывод. Это не так. :)Но есть много проектов с интересными идеями, которые могут подтолкнуть. Не нужно тащить к себе и пытаться использовать все подряд, а просмотр может оказаться полезным. Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Апрель 27, 2021, 09:28 Да, если нужны "и так и сяк", то есть приятная специфика - влазит в 64 бита. Напрашивается
Код И нахрюкать сеттеров которые обновляют m_bits; Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Апрель 27, 2021, 09:51 Я делаю через юнион писать в одно поле юниона, а читать из другого законно только в С, в С++ же (https://en.cppreference.com/w/cpp/language/union#Explanation):Цитировать It's undefined behavior to read from the member of the union that wasn't most recently written. Many compilers implement, as a non-standard language extension, the ability to read inactive members of a union. оно может и работает в clang/gcc/msvc, но полагаться на это не хочется :)как хранить "нормальные" члены класса не очень понял, ведь точно известно только то, что значение уместится в int64. "Нормальные" имелось ввиду что все песни с битами только для I/O, а так нормальные структуры. Пока неясно нужно ли битовое представление в памяти.думаю, что лучше иметь сырые битовые данные в одних структурах («сырых»), которые и будут читаться/писаться из/в файл, а бизнес-логику на других, более понятных структурах, которые будут конвертироваться из/в «сырые» структуры. Да, если нужны "и так и сяк", то есть приятная специфика - влазит в 64 бита. Напрашивается в 64 бита влезает одно поле, а структуры там побольше будутКод И нахрюкать сеттеров которые обновляют m_bits; Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Апрель 27, 2021, 10:24 нет, это только для I/O: Тогда не вижу в чем проблема, и зачем что-то искать. Пишем операторы потока для каждого класса - и все дела оно может и работает в clang/gcc/msvc, но полагаться на это не хочется Ну хорошо хоть так :) Не первый раз вижу это, и обычно делается вывод типа "юнионы не работают, применять их низзя" - таков обычный итог широких познаний :)в 64 бита влезает одно поле, а структуры там побольше будут Ну пришлось бы разориться на array или vector, смысл тот жеНазвание: Re: чтение и запись битовых структур данных Отправлено: kambala от Апрель 27, 2021, 10:50 Тогда не вижу в чем проблема, и зачем что-то искать. Пишем операторы потока для каждого класса - и все дела вот мы и пришли к вопросам из первого поста :)1) велосипед или готовое (частично ответили) 2) как сделать ширину поля частью структуры данных, а не частью парсера (попытки выше есть, комментариев к ним пока нет) Название: Re: чтение и запись битовых структур данных Отправлено: juvf от Апрель 27, 2021, 11:11 писать в одно поле юниона, а читать из другого законно только в С, в С++ же (https://en.cppreference.com/w/cpp/language/union#Explanation): Писать в одно поле юниона, а читать из другово (в моих примерах) законно в любом языке. То, о чем говориться по вашей ссылке к моему случаю не имеет отношения. Цитировать It's undefined behavior to read from the member of the union that wasn't most recently written. Many compilers implement, as a non-standard language extension, the ability to read inactive members of a union. оно может и работает в clang/gcc/msvc, но полагаться на это не хочется :)на поальцах, про эту граблю.... если Код: union S Если будет Код: union S В моем Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Апрель 27, 2021, 11:35 2) как сделать ширину поля частью структуры данных, Не уверен что стоит ставить такую цель. НапрКод Если заменить int, short и.т.п. на нечто "содержащее битовый размер" (а это темплейт, другого не видно) это изрядно загадит текст, во всяком случае оперировать с членами будет трудно. Не применить ли KISS-прынцып (столь любимый некоторыми из нас :)). Простецкий вариант Код Он не так уж плох и работать будет. Название: Re: чтение и запись битовых структур данных Отправлено: Old от Апрель 27, 2021, 11:50 kambala, поясните пожалуйста, как с таким требованием:
Причем размер не всех полей известен на момент компиляции. Только точно известно, что не бывает полей шире, чем 64 бита. вы планировали задавать размеры полей здесь? Код
Устанавливать максимальным? Тогда теряется смысл с наглядностью. Название: Re: чтение и запись битовых структур данных Отправлено: Авварон от Апрель 27, 2021, 12:49 Писать в одно поле юниона, а читать из другово (в моих примерах) законно в любом языке. То, о чем говориться по вашей ссылке к моему случаю не имеет отношения. Нет, не законно=) Это опять возвращает нас к разговору о reinterpret_cast и type punning. Единственный законный способ сделать type punning в современном с++ - это memcpy. В с++20 добавят bit_cast который сейчас можно написать самому через memcpy (https://en.cppreference.com/w/cpp/numeric/bit_cast) Код: template <class To, class From> То есть можно скопировать буфер в структуру через memcpy а вот записать int64_t а потом прочитать из битфилда на него наложеннный - нет. Но да, все известные мне компиляторы это позволяют делать. Но clang-tidy ругается AFAIK Название: Re: чтение и запись битовых структур данных Отправлено: juvf от Апрель 27, 2021, 13:08 То есть можно скопировать буфер в структуру через memcpy а вот записать int64_t а потом прочитать из битфилда на него наложеннный - нет. А в чем косяк такого метода? Я понимаю когда объединили int и long. Но когда Но да, все известные мне компиляторы это позволяют делать. Но clang-tidy ругается AFAIK Это не то, чтобы "в с/с++ это предусмотрено и так нужно делать", это безопасный лайфхак. Если размер битовой структры 64 бита, и объединённого члена 64 бита, то компилятор не то что не позволит это сделать, или что-то испортит - а куда он денется с подводной лодки? Название: Re: чтение и запись битовых структур данных Отправлено: Авварон от Апрель 27, 2021, 13:15 Это не то, чтобы "в с/с++ это предусмотрено и так нужно делать", это безопасный лайфхак. Если размер битовой структры 64 бита, и объединённого члена 64 бита, то компилятор не то что не позволит это сделать, или что-то испортит - а куда он денется с подводной лодки? все ненавистное UB нужно для оптимизаций. Можно тот пример с reinterpret_cast переписать на union: Код: union U { Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Апрель 27, 2021, 13:17 Не применить ли KISS-прынцып (столь любимый некоторыми из нас :)). Простецкий вариант сейчас у меня примерно так и сделано, но не считаю, что это хорошее решение, надо попробовать поискать получше :)kambala, поясните пожалуйста, как с таким требованием: тот пример — для известных размеров. для неизвестных, думаю, надо немножко другой контейнер, который позволит задавать ширину поля в конструкторе. подлежащий тип будет максимальным, да. наглядности с неизвестными не достичь, конечно :)вы планировали задавать размеры полей здесь? Устанавливать максимальным? Тогда теряется смысл с наглядностью. Название: Re: чтение и запись битовых структур данных Отправлено: juvf от Апрель 27, 2021, 13:24 Цитировать 0 или -1? 0Цитировать type punning понятно... да это вариант с type punningНазвание: Re: чтение и запись битовых структур данных Отправлено: Igors от Апрель 27, 2021, 15:24 тот пример — для известных размеров. для неизвестных, думаю, надо немножко другой контейнер, который позволит задавать ширину поля в конструкторе. подлежащий тип будет максимальным, "Неизвестный" = содержит массив(ы) переменной длины, счетчик должен читаться/писаться в поток. Или есть др варианты?Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Апрель 27, 2021, 15:27 Цитировать 0 или -1? ответом будет:Код: untitled 2:4:11: error: initializing multiple members of union предлагаю вам ваше обсуждение об играх с юнионом перенести в другой тред :) "Неизвестный" = содержит массив(ы) переменной длины, счетчик должен читаться/писаться в поток. Или есть др варианты? не понял, счетчик чего?неизвестный на момент компиляции, в рантайме читается из конфигурационных файлов (они всегда доступны). Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Апрель 27, 2021, 15:28 P.S. вопрос знатокам :) как задать массив (обычный или std::array) из std::byte по-человечески? у меня получается только с явным вызовом конструктора для каждого элемента как в коде выше. ([unsigned] char предлагать не надо :) ) нашел ответ (https://stackoverflow.com/a/46151026/1971301): это так бай дизайн. лучше тогда брать uint8_t.Код
Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Апрель 27, 2021, 16:02 не понял, счетчик чего? Счетчик эл-тов массива/контейнера - члена классанеизвестный на момент компиляции, в рантайме читается из конфигурационных файлов (они всегда доступны). А существующие файлы записанные с "конфигурацией X"? Выходит в поток все равно надо писать кол-во бит.сейчас у меня примерно так и сделано, но не считаю, что это хорошее решение, надо попробовать поискать получше :) Может смущает просто отсутствие новомодных цацок? :) Ну допустим даже удалось как-то объявить - от (полного) написания почленного I/O это все равно не избавит. И как битовые размеры (автоматом) сплавить для I/O - тоже хз.Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Апрель 27, 2021, 16:20 Счетчик эл-тов массива/контейнера - члена класса теперь понял. формат данных уже содержит такое поле.А существующие файлы записанные с "конфигурацией X"? Выходит в поток все равно надо писать кол-во бит. да, именно с такой конфигурацией. задачи конвертации между конфигурациями не стоит (но в принципе сделать можно).Может смущает просто отсутствие новомодных цацок? :) Ну допустим даже удалось как-то объявить - от (полного) написания почленного I/O это все равно не избавит. И как битовые размеры (автоматом) сплавить для I/O - тоже хз. отсутствие не смущает, но не вижу ничего плохого в том, чтобы исследовать что в них есть и как ими можно воспользоваться для улучшения кода, уменьшения писанины и увеличения наглядности/читабельности :)надеюсь схитрить как-то через массив, задающий порядок полей, что-то типа: Код: for field in mystruct.orderedFields Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Апрель 27, 2021, 16:39 отсутствие не смущает, но не вижу ничего плохого в том, чтобы исследовать что в них есть и как ими можно воспользоваться для улучшения кода, уменьшения писанины и увеличения наглядности/читабельности :) Да, я иногда тоже так рыпаюсь, пусть без особого успеха - но интереснонадеюсь схитрить как-то через массив, задающий порядок полей, что-то типа: Категорически утверждать "нельзя" не буду, но если и можно, то там такое мракобесие (https://habr.com/ru/post/344206/) , что ну его нафиг, ото тупенько почленно расписать - сохранить и голову и времяКод: for field in mystruct.orderedFields Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Апрель 27, 2021, 19:07 Категорически утверждать "нельзя" не буду, но если и можно, то там такое мракобесие (https://habr.com/ru/post/344206/) , что ну его нафиг, ото тупенько почленно расписать - сохранить и голову и время спасибо, попробую. необязательно разбирать шаблоны сверхразума внутри библиотеки, если она решает требуемую задачу :)Название: Re: чтение и запись битовых структур данных Отправлено: Old от Апрель 27, 2021, 20:40 А давайте попробуем придумать, как удобно можно описывать и использовать такие битовые структуры.
Вот один из возможных вариантов, так сказать для затравки (здесь пока все размеры полей задаются при компиляции): Код
Название: Re: чтение и запись битовых структур данных Отправлено: juvf от Апрель 28, 2021, 06:43 Цитировать 0 или -1? ответом будет:Код: untitled 2:4:11: error: initializing multiple members of union union U { int i{0}; float f; }; Тут нет ошибки. Название: Re: чтение и запись битовых структур данных Отправлено: ssoft от Апрель 28, 2021, 07:21 На эту тему писал свой велик. Продукт проприетарный, поэтому пока опишу только сами подходы.
Реализовывалась работа со структурами специфичного формата данных http://www.eurocontrol.int/services/asterix Формат данных описывается в параметрическом виде, например, xml Код
Для этого файла пишется парсер, который формирует структуры с описанием формата данных. Сами данные представляются в виде последовательности байт, которая обобщена между полями структуры. Поле структуры - это, собственно, ссылка на описание формата данных и на место размещения этих данных в памяти. Если требуется работать с динамически изменяющимися структурами, то доступ к полям в runtime осуществляется по имени примерно так Код
Если состав структуры известен на этапе компиляции, то по формату xml можно сгенерировать исходники, как предлагал Old или так Код
Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Апрель 28, 2021, 10:37 необязательно разбирать шаблоны сверхразума внутри библиотеки, если она решает требуемую задачу :) Это довольно скользкое место :) Если либа достаточно представительна, авторитетна - то да, можно просто "полагаться". А иначе...Но главное не это. Не скрою, начало статьи (пример: печать любой, произвольной структуры) впечатляет. Но если немного поразмыслить, то применимость этого - ну, мягко говоря, невелика. Обычно десериализация выглядит так Код Т.е. заливка из потока - вовсе не "однообразный цикл" по членам. Находятся какие-то подробности которые в общий механизм не ложатся. Пусть их не так уж много, но без них не обойтись. Именно эта "соломинка" часто ломает спину темплейтовскому верблюду :) Код
Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Апрель 29, 2021, 13:35 А давайте попробуем придумать, как удобно можно описывать и использовать такие битовые структуры. примерно так и представляется. но хотелось бы избавиться от необходимости явного перечисления полей (пока берем идеальный вариант, где нет никаких записей кусками по условиям, хотя их тоже можно нарезать на более мелкие структуры).Вот один из возможных вариантов, так сказать для затравки (здесь пока все размеры полей задаются при компиляции): Код
вариант 1 (был выше): Код: for field in mystruct.orderedFields вариант 2: заставить кого-то типа Boost.pfr или Boost.Hana (в последней пока ничего не понял из просмотра документации :) ) сформировать порядок полей из описания структур в момент компиляции. На эту тему писал свой велик. Продукт проприетарный, поэтому пока опишу только сами подходы. спасибо. по сути, описываем структуру во внешнем файле и генерируем для нее парсер и С++ структуры данных. насколько я понимаю, генератор не содержит ни одного зашитого поля, все читается из внешнего файла — вполне хороший способ! хоть и немного громоздкий :)но если удастся описать структуру полностью в рамках С++, то и кодогенератор не понадобится. Т.е. заливка из потока - вовсе не "однообразный цикл" по членам. Находятся какие-то подробности которые в общий механизм не ложатся. Пусть их не так уж много, но без них не обойтись. Именно эта "соломинка" часто ломает спину темплейтовскому верблюду :) так можно ж комбинировать: «магические шаблоны» делают свою работу, нестандартные вещи дописать руками.Название: Re: чтение и запись битовых структур данных Отправлено: Old от Апрель 29, 2021, 15:12 вариант 1 (был выше): Код: for field in mystruct.orderedFields Наверное такое проще всего реализовать через базовый класс для структур: Код
Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Апрель 29, 2021, 16:24 но хотелось бы избавиться от необходимости явного перечисления полей Такие планы должны иметь более достойные цели чем "битовое чтение/запись"... по сути, описываем структуру во внешнем файле и генерируем для нее парсер и С++ структуры данных. .. Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Май 05, 2021, 13:58 написал парсер с помощью boost.pfr, пока все выглядит отлично :)
«библиотечный» код: Код
парсер: Код
далее надо поместить распарсенное куда-то и обобщить парсер для чтения и записи. Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Май 05, 2021, 14:29 Код: // bit structs Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Май 05, 2021, 15:10 просто глядя на такую struct, и человек, и машина (код) сразу понимают суть — по-моему это намного удобнее, чем лезть в код парсера и искать размеры полей. плюс автоматическое определение нужного размера подлежащего типа (будет жрать меньше памяти, чем просто засунуть uint64_t во все поля).
Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Май 06, 2021, 18:15 просто глядя на такую struct, и человек, и машина (код) сразу понимают суть — по-моему это намного удобнее, чем лезть в код парсера и искать размеры полей. плюс автоматическое определение нужного размера подлежащего типа (будет жрать меньше памяти, чем просто засунуть uint64_t во все поля). Это типа "двигатели на машинки" ставить, т.е. да, разумно, полезно, но... Не навязываю своего мнения, но достигаемый ф-ционал мне кажется слишком малым чтобы оправдать создание цепочки классов. К тому же является ли оно "сутью" - довольно спорно. Напр вполне возможно что структуры имеют смысл и без игр с битами. И иметь размеры полей в объявлении = хорошо, но это только для статики.Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Май 07, 2021, 10:26 Попробуем усилить вариант что не гадит темплейтами
Код
Код Чтобы избавиться от тучи enum'ов. Да, мапу придется заполнять из настроек, ну это неизбежно. Да, легко найти "сколько бит для поля" не получится, но можно напечатать всю мапу. И если нужен "авто-слив" (без почленной сериализации) - его легко сделать с мапой Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Май 08, 2021, 12:48 для меня ваш код выглядит намного менее понятно, чем темплейты :) typeid так и вовсе никогда в жизни не пользовался (щас бегло посмотрел что это и заметил, что специально для ключа словаря придумали std::type_index, потому что на адрес нельзя закладываться). Если он скрыт в оттестированной библиотеке — буду спокойно пользоваться.
и "авто-слив", и печать, через boost.pfr тоже доступны. а заполнить theGlobalBitsMap без создания объекта не получится, я так понял. то есть выглядит как-то так: Код и тут прямо напрашиваются макросы для улучшения читабельности :) сюда тоже нужен макрос, ибо ошибку копипастой сделать очень легко: Код хотя может получится скрыть за функцией, принимающей указатель на член, может ее и затемплейтить можно, чтоб не вставлять в каждую нужную структуру. по-моему получается очень много ненужной ручной работы плюс доступность лишь в рантайме. Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Май 08, 2021, 16:05 специально для ключа словаря придумали std::type_index, потому что на адрес нельзя закладываться Не вижу где написано что адрес может уплыть, но в любом случае type_index смотрится приятнее.хотя может получится скрыть за функцией, принимающей указатель на член, может ее и затемплейтить можно, чтоб не вставлять в каждую нужную структуру. Конечно, напр такКод
по-моему получается очень много ненужной ручной работы плюс доступность лишь в рантайме. Ручная работа = регистрации каждого поля что пишется в биты (одна строка SetBitsCount). Выгода (по сравнению с Вашим вариантом) в том что ничего не навязывается. Простой, житейский сюжет- Жили-были обычные, нормальные структуры, все работало. Но в один прекрасный день возникла необходимость читать/писать в биты. Хорошо ли менять все обычные int и др на BitField<>? Очевидно нет, это "архитектурно неграмотно" т.к. меняем фундаментальные данные в угоду сиюминутной потребности. А если для структур написано достаточно много кода - такая замена уже нереальна. Да, и поверьте, где разбить коленки об темплейты - всегда найдется :) и "авто-слив", и печать, через boost.pfr тоже доступны. Прошу показать (можно вкратце), интересно кака заполнить theGlobalBitsMap без создания объекта не получится, Может и можно, но лично я не знаю как. Есть какой-то мутный offsetof, но вроде он "не часть стандарта". Собсно нужно "идентифицировать поле"для меня ваш код выглядит намного менее понятно, чем темплейты :) Что же такого непонятного я написал? :)Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Май 08, 2021, 19:25 Цитировать Не вижу где написано что адрес может уплыть https://en.cppreference.com/w/cpp/language/typeid Notes:Цитировать There is no guarantee that the same std::type_info instance will be referred to by all evaluations of the typeid expression on the same type, although std::type_info::hash_code of those type_info objects would be identical, as would be their std::type_index. Код
Цитировать Простой, житейский сюжет но это не мой сюжет :) сырые битовые структуры и те, с которыми удобно работать — разные сущности.Цитировать Прошу показать (можно вкратце), интересно как "авто-слив" в приведенном парсере уже по сути есть:Код можно и пользовательский вывод определить (не пробовал): https://www.boost.org/doc/libs/develop/doc/html/boost_pfr/tutorial.html#boost_pfr.tutorial.custom_printing_of_aggregates и следующий раздел стандартный вывод просто печатает все поля по порядку: Код
Цитировать Что же такого непонятного я написал? все эти игры с typeid и указателями на члены, никогда не сталкивался :)Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Май 09, 2021, 09:52 https://en.cppreference.com/w/cpp/language/typeid Notes: Да, верно, спасибо"авто-слив" в приведенном парсере уже по сути есть: Ага, вот он, "момент истины". Оказывается дуст умеет "перебирать по полям" как я видел в статейке. А просто так заграбастать эту ф-цию нельзя? Пусть с мапой тоже несложно, но так еще лучше.Код
Хотя это совсем не означает что нужно искалечить все нормальные члены только для того чтобы иметь битовый размер. Кстати для статики почему бы не задействовать простецкие bitfield (от которых Вы гордо отказались). Напр Код И для мапы - только m_value. Это заметно схлопнет число всяких мелких полей. А на понты про union не обращайте внимания, то так, "что-то читал" :) но это не мой сюжет :) сырые битовые структуры и те, с которыми удобно работать — разные сущности. Ну а зачем иметь/заводить 2 представления данных ? Я бы этого всячески избегал Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Май 09, 2021, 11:25 потому что на адрес нельзя закладываться Да, посмотрел старый код, там у мапы есть еще функторКод Т.е. можно и так, хотя type_index явно удобнее Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Май 09, 2021, 23:35 Цитировать Кстати для статики почему бы не задействовать простецкие bitfield (от которых Вы гордо отказались) не очень понял как ваш пример мне поможет в случае, когда последнее поле не влезает в границу uint32 или uint64 (например, для uint32 индекс 30 и размер 5), или если структура больше 64 бит. как читать CFlag — тоже непонятно (fread? >>? проблемы с endianness опустим), плюс придется самому считать размеры таких полей чтоб все влезло (опять же, ненужная ручная работа). прошу продемонстрировать ©если предполагается писать в m_value, а читать из битовых полей, то в С++ остается только верить, что компилятор сделает как ожидается, но давайте писать код, следующий стандарту :) Либо надо писать парсер на С, где такой трюк абсолютно законен. Цитировать И для мапы - только m_value связь с мапой не уловилЦитировать Ну а зачем иметь/заводить 2 представления данных ? Я бы этого всячески избегал с сырыми данными в моем случае крайне неудобно работать, их надо преобразовывать в более подходящие для «пользовательского» кода структуры.Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Май 10, 2021, 10:24 опять же, ненужная ручная работа Может быть. Но гонять (большие) структуры сырые<->рабочие - мало не покажется, считаю оно того стоит.не очень понял как ваш пример мне поможет в случае, когда последнее поле не влезает в границу uint32 или uint64 (например, для uint32 индекс 30 и размер 5), или если структура больше 64 бит. как читать CFlag — тоже непонятно (fread? >>? проблемы с endianness опустим), плюс придется самому считать размеры таких полей чтоб все влезло (опять же, ненужная ручная работа). прошу продемонстрировать © Чтение/запись получает адрес и число бит (не байт) которое берется из мапы. Стандартные операторы >> здесь применить не выйдет т.к. в одном байте могут сидеть части 2 структур. Для bitfield я бы делал такесли предполагается писать в m_value, а читать из битовых полей, то в С++ остается только верить, что компилятор сделает как ожидается, но давайте писать код, следующий стандарту :) Либо надо писать парсер на С, где такой трюк абсолютно законен. 1) ограничил вместимость CFlag 32 битами. Если битовое поле >= инта, то почти наверняка компилятор как-то будет его равнять, и непрерывный битовый массив мы не получим, связываться с этим не стоит. Это нормально, делать большие члены битовыми неразумно. 2) Сделал бы последним членом подставу, напр m_padding, так чтобы сумма размеров = 32. Да, его размер придется вычислять руками, есть такая "шероховатость" :) Ну и считаем число бит Код
Интереснее как писать более продвинутые члены, напр контейнеры Название: Re: чтение и запись битовых структур данных Отправлено: Авварон от Май 10, 2021, 11:16 Может быть. Но гонять (большие) структуры сырые<->рабочие - мало не покажется, считаю оно того стоит. Это называется "абстракция". Завтра вам надо другой формат поддерживать - удачи менять все структуры. На самом деле такие "битовые" операции даже в моей текущей области (спутники) нужны (правда тут тупо кодом все читается, без декларативных структур) и вот у вас условно 10 похожих но разных форматов расположения битовых полей. Условно идет Хедер1 по которому мы понимаем идет ли дальше Хедер2А или Хедер2Б. В итоге всё это льется в огромный объект с кучей свойств - в зависимости от какие-то свойства есть, каких-то нет. Причем одни и те же свойства в разных вариантах на разной битовой позиции, ох я бы не хотел работать с битовыми структурами напрямую Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Май 10, 2021, 12:16 Это называется "абстракция". Завтра вам надо другой формат поддерживать - удачи менять все структуры. Не понял что Вы хотели сказать :) Лично я считаю что данные должны существовать только в одном виде/экземпляре, а побитовый I/O - всего лишь один из вариантов (де)сериализации. Поэтому вариант с BitField<> (создание массивных структур чисто для I/O) осуждаю (ну осуждать много ума не надо :))Тут вот какая мысля. Для пачки битовых полей считаем размер автоматом. Так может и для др полей тоже? Чтобы избавиться от утомительной "регистрации" и заполнять мапу автоматом. Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Май 10, 2021, 13:32 Цитировать Чтение/запись получает адрес и число бит (не байт) которое берется из мапы то есть теперь эти оффсеты надо вычислять самому для заполнения мапы (да, делается один раз, но...), а не просто пользоваться руководством по требуемому битовому формату. а сколько будет веселья, если надо будет чуть-чуть их поменять, а они не влезут в вычисленные нами границы байт... :)Цитировать в одном байте могут сидеть части 2 структур все для людей!Цитировать Если битовое поле >= инта, то почти наверняка компилятор как-то будет его равнять, и непрерывный битовый массив мы не получим, связываться с этим не стоит. Это нормально, делать большие члены битовыми неразумно. нет, я решительно не хочу думать что там компилятор выравнивает и куда, я хочу решать свою прикладную задачу — просто напишу BitField<34>.Цитировать Сделал бы последним членом подставу, напр m_padding еще и паддинг самому считать... :)Цитировать Ну и считаем число бит вообще не понял что эта функция делает. при чем там -1 и число единиц?Цитировать Интереснее как писать более продвинутые члены, напр контейнеры просто читаем элементы подряд. но тут темплейты, такой код слишком Код конечно, каждому контейнеру надо будет писать свою реализацию. но тут можно блеснуть словом «концепт», сказав, что мы поддерживаем любую структуру данных, которая имеет метод auto parse(gsl::span<uint8_t> const& sp, uint64_t& offset). (кстати, на эту же тему недавно нашел нечто похожее на протоколы из objc/swift: https://github.com/ldionne/dyno) Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Май 10, 2021, 14:36 то есть теперь эти оффсеты надо вычислять самому для заполнения мапы (да, делается один раз, но...), а не просто пользоваться руководством по требуемому битовому формату. Такое "руководство" по-любому будет, только я предлагаю написать его как создание мапы, а не создавать новые типы, а потом еще перегонять данные. а сколько будет веселья, если надо будет чуть-чуть их поменять, а они не влезут в вычисленные нами границы байт... :) Да, придется немного подсуетиться. Но гораздо вероятнее вариант "изменилось но еще влезает" - и мне ничего делать не надо, а Вам...еще и паддинг самому считать... :) Никто не заставляет, можно тупенько почленно, просто заманчиво резко сократить число строк "руководства".просто напишу BitField<34>. Да, отказаться от уже написанного кода непросто :)Название: Re: чтение и запись битовых структур данных Отправлено: kambala от Май 10, 2021, 15:47 у меня нет никакого «написанного» кода, есть пока лишь пара тестовых примеров. но ваш подход кажется чрезмерно переусложненным по сравнению с декларативным темплейтным. демонстрации аналога http://www.prog.org.ru/index.php?topic=33021.msg244833#msg244833 также не последовало.
дальнейший спор считаю бессмысленным, победила дружба :) Название: Re: чтение и запись битовых структур данных Отправлено: Igors от Май 11, 2021, 07:21 у меня нет никакого «написанного» кода, есть пока лишь пара тестовых примеров. но ваш подход кажется чрезмерно переусложненным по сравнению .. Возможно Вы "по инерции" считаете что есть "сырые" и "рабочие" данные, но я предлагаю иметь только рабочие. Сравним 2 вариантаКод: struct BasicBitItem Код: BasicBitItem item; Правда возможно что "битовый размер" - еще не все что нужно I/O. Вполне вероятно что читаются/пишутся поля которых нет в рабочих данных, и наоборот. И в моем варианте неясно как уложить такие в "руководство". Ну проблема их заполнения все равно остается. Но это уже чисто мои догадки :) дальнейший спор считаю бессмысленным, победила дружба :) Согласен :) |