В этой статье речь пойдет не о wxWidgets, а о "чистом" C++. А именно о классе, производном от std::bitset. Зачем это мне понадобилось и может понадоить кому-нибудь еще речь пойдет немного позже. А пока я хочу зделать маленькое отступление
Думаю, рано или поздно каждый программист создает свой репозитарий. И приходится думать о том, как удобнее размещать свои наработки для использования в дальнейшем. Я не буду говорить о том, как именно я организовую свое хранилище, но одним из личных правил есть пространство имен, т.е. все свои классы, функции и т.п. я размещаю в одном пространтсве имен, котороя я назвал rpz
Итак, вернемся к предмету статьи, вернее, к причинам, побудившим меня написать свой битовый набор. Как правило, я чаще всего его использую при управлением доступом. По-моему, очень удобно управлять доступом пользователя к пунктам меню, если хранить в базе данных таблицу пользователей и таблицу из которой выгружается меню. Подозреваю, что большинству программистов, пишущих на MFC эта идея, скорее всего, не понравится). Хотя и под этой иблиотекой мне пришлось заниматься такими манипуляциями. Однажды мне пришлось писать программу, используя wxWidgets и СУБД FireBird. В этой среде управление пользователями и доступом к меню писать было гораздо приятнее. Однако более удобной организации доступа к пунктам меню, чем записывать в БД преобразованный битовый набор к числу я не нашел. И тут я столкнулся со следующей трудностью. Битовый набор, предоставляемый STL можно легко инициализировать типом unsigned long или строкой бит. Ну, а если у меня будет больше, чем 32 пункта меню? Почему бы не зделать возможность инициализации битового набора каким-либо другим типом, например __int64? Но ведь пунктов меню в серьезной программе может быть и больше 64-х. Потому и пришла мне мысль написать свой битовый набор, который можно инициализировать не только числовыми типами, но и массивом байт, например. Словом, всем, что приводится к void*).
Теперь о главном. Сами понимаете, что писать подобный класс "с нуля" вещь не очень приятная. А воспользоваться чем-нибудь готовым - милое дело. Потому свое детище, имя которому rpz::BitSet, я произвел от std::bitset. И, как уже, наверное, догадываетесь, это шаблонный класс.
rpzBitSet.h
/***************************************************************
* Name: rpzBitSet.h
* Purpose: BitSet for sizeof(T) > sizeof(long)
* Author: developer@sandyhip.net.ua
* Created: 13/10/2009
* Copyright: www.sandyhip.net.ua
* License: BSD
**************************************************************/
#ifndef RPZ_BITSET
#define RPZ_BITSET
#include <bitset>
#include <stdexcept>
namespace rpz {
template<const size_t N, const size_t Nb = 8> class BitSet: public std::bitset<N> {
/// N - размер в битах
/// Nb - количество бит в одном байте (8)
public:
/// Конструктор по умолчанию
BitSet() : std::bitset<N> ()
{
if (N % Nb != 0) {
throw std::out_of_range("Size must be a multiple amount bit!");
}
}
/// Конструктор, инициализирующий битовый набор значением
explicit BitSet(const void* pVal, const size_t nByte) : std::bitset<N> ()
{
if (N % Nb != 0) {
throw std::out_of_range("Size must be a multiple amount bit!");
}
try {
SetValue(pVal,nByte);
}
catch (std::exception& e) {
throw e;
}
}
/// Destructor
~BitSet() {}
/// Функия, инициализирующая битовый набор значением
void SetValue(const void* pVal, const size_t nByte)
{
if (nByte * Nb > N) {
throw std::out_of_range("Size byte does not correspond to size a bit!");
}
char* cByte = new char[nByte];
memcpy(cByte, pVal, nByte);
this->reset();
for (size_t t = 0; t < nByte; t++) {
for (size_t i = 0, j = Nb * t; i < Nb; i++, j++) {
this->set(j, cByte[t] >> i & 0x01);
}
}
delete[] cByte;
}
/// Функция, возвращающая значение
void GetValue(void* pVal, const size_t nByte)
{
if (nByte * Nb > N) {
throw std::out_of_range("Size byte does not correspond to size a bit!");
}
char* cByte = new char[nByte];
for (size_t t = 0; t < nByte; t++) {
cByte[t] = 0;
for (size_t i = 0, j = Nb * t; i < Nb; i++, j++) {
cByte[t] |= ((*this)[j] << i);
}
}
memcpy(pVal, cByte, nByte);
delete[] cByte;
}
/// Функция, преобразующая строку бит в набор
void SetString(const char* sVal)
{
const size_t nBit = strlen(sVal);
if (nBit > N) {
throw std::out_of_range("Size of the bit line out of range!");
}
this->reset();
for (size_t i = 0; i < nBit; i++) {
this->set((nBit-i)-1, ((sVal[i]=='1') ? true : false));
}
}
/// Функция, возвращающая строку бит
const char* GetString()
{
std::string s = this->template
to_string<char,std::char_traits<char>,std::allocator<char> >();
return s.c_str();
}
};
}
#endif // RPZ_BITSET
Вот и все. Остальной функционал предоставляет базовый класс - std::bitset. Использовать его так:
Exmple.cpp
#include <rpzBitSet>
#include <iostream>
/* ... */
unsigned __int64 n = 0;
rpz::BitSet<64> bit;
bit.set();
bit.GetValue(&n,sizeof(n));
std::cout << n << '\n' << bit.GetString() << "\n\n";
if (n != ULONG_LONG_MAX) std::cout << "Error!\n";
int d = 5;
bit.SetValue(&d,sizeof(d));
std::cout << d << '\n' << bit << "\n\n";
/* ... */


