Я написал этот класс некоторое время назад, когда мне нужно было разбираться с битами. Это может быть полезно и вам. Вот оно:
#include <deque>
#include <vector>
#include <algorithm>
class bitStream {
public:
bitStream() {}
/// Copies the data from another bitStream into this one upon construction
bitStream(const bitStream& bStream, bool reverse=false) {
this->appendData(bStream, reverse);
}
/// Copies the data from a vector of booleans upon construction
bitStream(const vector<bool>& vec, bool reverse=false) {
this->appendData(vec, reverse);
}
/// Appends data to the stream from a uint64_t type. The lower-n bits will be appended, starting with the highest bit of those by default.
void appendData(uint64_t data, size_t n, bool reverse=false) {
deque<bool> _buffer;
n = (n>64)?64:n;
for (int i=0; i<n; i++) {
_oneBit tmp;
tmp.data = data;
_buffer.push_back(tmp.data);
data >>= 0x1;
}
if (!reverse) std::reverse(_buffer.begin(), _buffer.end());
for (const auto v: _buffer) _data.push_back(v);
}
/// Appends data to the stream from a C-style array of booleans
void appendData(bool* data, size_t n, bool reverse=false) {
if (reverse) {
for (int i=0; i<n; i++) this->appendBit(*(data+(n-i-1)));
} else {
for (int i=0; i<n; i++) this->appendBit(*(data+i));
}
}
/// Appends data to the stream from a vector of booleans
void appendData(const vector<bool>& vec, bool reverse=false) {
if (reverse) {
for (auto i = vec.size()-1; vec.size() > i; --i) this->appendBit(vec.at(i));
} else {
for (const auto& v : vec) this->appendBit(v);
}
}
/// Appends a single bit
void appendBit(bool bit) {
_data.push_back(bit);
}
/// Appends the bits from another bitStream object to this one
void appendData(const bitStream& bStream, bool reverse=false) {
if (!bStream.getSize()) return;
if (reverse) {
for (int i=0; i<bStream.getSize(); i++) this->appendBit(*(bStream.getData()+(bStream.getSize()-i-1)));
} else {
for (int i=0; i<bStream.getSize(); i++) this->appendBit(*(bStream.getData()+i));
}
}
/// Returns a pointer to the begining of the data (read-only!)
const bool* getData() const { return &_data.front(); }
/// Reference to the bit at a specified position (assignable, but at lest n+1 elements must exist before calling!)
bool& operator[] (size_t n) {
if (n>_data.size()-1) throw runtime_error("Out of range!");
return _data.at(n);
}
/// Fills your vector with the data chopped up into "sizeof(T)"-byte pieces.
template <typename T>
void getDataAsVector(vector<T>& vec) {
vec.clear();
size_t oSize = sizeof(T)*8;
T tmp = 0x0;
for (int i=0; i<_data.size(); i++) {
if (!(i%oSize) && i) {
vec.push_back(tmp);
tmp = 0x0;
}
tmp <<= 0x1;
tmp |= _data[i];
}
vec.push_back(tmp);
}
/// Returns the number of bits that are stored
size_t getSize() const { return _data.size(); }
/// Reverses the stored bits
void reverse() { std::reverse(_data.begin(), _data.end()); }
private:
deque<bool> _data;
struct _oneBit {
uint8_t data:1;
};
};
Это довольно тривиально использовать, поэтому я не стал писать пример.
Прежде всего, я никогда не использовал его в проекте, поэтому там могут быть некоторые ошибки (я помню только его тестирование очень кратко), плюс он еще не закончен полностью (существует несколько возможных конструкторов что я не реализовал). Кроме того, несмотря на название «поток», он не имеет ничего общего с потоком на C++.
Таким образом, в основном это позволяет хранить бит.Биты, которые вы вставляете в него, будут храниться на смежных адресах памяти (да, это один бит на каждый бит памяти, но что угодно), которые остаются неизменными для времени жизни объекта (это связано с тем, что deque
не перераспределяет себя в отличие от vector
)! Вы можете добавлять биты к нему различными способами (из разных источников данных, в обратном или обратном порядке) и читать их в разных формах. В вашем случае функция appendData(uint64_t data, size_t n, bool reverse=false)
- это та, которую вы можете использовать, чтобы заполнить ее. Чтобы вернуть данные, вы можете получить vector<char>
с данными, нарезанными в 1-байтовые фрагменты (символы), если хотите!
Опять же, пожалуйста, не принимайте это за 100% проверенную и работоспособную вещь. Я только проверил его ненадолго, поэтому вы должны попробовать его и посмотреть, работает ли он для вас! Я думал, что поделюсь им с вами, если вы сочтете это полезным.
Можете ли вы изменить типы данных, с которыми работаете? – adam10603
Можете ли вы использовать [std :: bitset] (http://www.cplusplus.com/reference/bitset/bitset/)? – NathanOliver
Я не знаю ни одного легкого трюка. Вы должны либо использовать какую-то структуру данных бит-упаковки, либо собрать биты oldskool style. –