Двоичная сериализация std :: bitset - PullRequest
12 голосов
/ 09 марта 2011

std::bitset имеет метод to_string() для сериализации в виде строки char на 1 с и 0 с. Очевидно, что при этом используется один 8-битовый char для каждого бита в наборе битов, что делает сериализованное представление в 8 раз длиннее необходимого. Я хочу сохранить набор битов в двоичном представлении для экономии места. Метод to_ulong() применим только тогда, когда в моем наборе битов меньше 32 бит. У меня есть сотни.
Я не уверен, что хочу использовать memcpy() / std::copy() на самом объекте (адресе), поскольку это предполагает, что объект является POD.

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

Мне также хотелось бы, чтобы опция десериализации набора битов была представлена ​​в двоичном представлении.

Как я могу это сделать?

Ответы [ 5 ]

7 голосов
/ 18 сентября 2011

Это возможный подход, основанный на явном создании std::vector<unsigned char> путем чтения / записи по одному биту за раз ...

template<size_t N>
std::vector<unsigned char> bitset_to_bytes(const std::bitset<N>& bs)
{
    std::vector<unsigned char> result((N + 7) >> 3);
    for (int j=0; j<int(N); j++)
        result[j>>3] |= (bs[j] << (j & 7));
    return result;
}

template<size_t N>
std::bitset<N> bitset_from_bytes(const std::vector<unsigned char>& buf)
{
    assert(buf.size() == ((N + 7) >> 3));
    std::bitset<N> result;
    for (int j=0; j<int(N); j++)
        result[j] = ((buf[j>>3] >> (j & 7)) & 1);
    return result;
}

Обратите внимание, что для вызова функции шаблона десериализации bitset_from_bytes размер набора битов N должен быть указан в вызове функции, например

std::bitset<N> bs1;
...
std::vector<unsigned char> buffer = bitset_to_bytes(bs1);
...
std::bitset<N> bs2 = bitset_from_bytes<N>(buffer);

Если вы действительно заботитесь о скорости, то одно решение, которое получит что-то, будет делать развертывание цикла, чтобы упаковка выполнялась, например, по одному байту за раз, но еще лучше написать собственную реализацию набора битов, которая не скрыть внутреннее двоичное представление вместо использования std::bitset.

2 голосов
/ 11 октября 2011

Как предложили ребята из gamedev.net, можно попробовать boost :: dynamic_bitset , поскольку он позволяет получить доступ к внутреннему представлению битовых данных.

1 голос
/ 10 марта 2011

edit: Следующее не работает должным образом.По-видимому, «двоичный формат» фактически означает «двоичное представление ASCII».


Вы должны быть в состоянии записать их в std::ostream, используя operator<<.Здесь написано здесь :

[Биты] также могут быть непосредственно вставлены и извлечены из потоков в двоичном формате.

1 голос
/ 17 сентября 2011

Отвечая на мой вопрос о полноте.

По-видимому, не существует простого и портативного способа сделать это.

Для простоты (хотя и не эффективности) я закончил с использованием to_string, а затем создал последовательные 32-битные наборы битов из всех 32-битных фрагментов строки (и остальных *) и использовал to_ulong на каждом из них, чтобы собрать биты в двоичный буфер.
Этот подход оставляет переключение битов на самом STL, хотя, вероятно, это не самый эффективный способ сделать это.

* Обратите внимание, что, поскольку std::bitset настроен на общее количество битов, для остального набора битов необходимо использовать простую арифметику метапрограммирования шаблона.

0 голосов
/ 09 марта 2011

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

РЕДАКТИРОВАТЬ: Лучше просто перебрать все биты с operator[] и вручную его сериализовать.

...