Skip to content

Instantly share code, notes, and snippets.

@PlugFox
Last active June 4, 2019 16:36
Show Gist options
  • Save PlugFox/13363e58a2f8a454a518444a90282825 to your computer and use it in GitHub Desktop.
Save PlugFox/13363e58a2f8a454a518444a90282825 to your computer and use it in GitHub Desktop.
Побитовое хранилище int и bool
/*
* Побитовое хранилище int и bool
* https://gist.github.com/PlugFox/13363e58a2f8a454a518444a90282825
* https://dartpad.dartlang.org/13363e58a2f8a454a518444a90282825
*/
/*
+-------------------------
| ВЫВОД //
+-------------------------
| Исходные данные: 2235, 62, 13, 1, true
| Восстановленные данные: 2235, 62, 13, 1, true
| Хранилище: XX0XXX0X-000X0XXX-XXX0XXXX
| Размер хранилища: 3 байт.
| Хранилище набором байт: [187, 232, 247]
| Хранилище бит строкой: 111101111110100010111011
| Хранилище в HEX: 0xF7E8BB
| Человекопонятное представление: Xy@Z
+-------------------------
*/
void main() async {
/* Исходные данные */
int i_12 = 2235; // 12 бит
int i_6 = 62; // 6 бит
int i_4 = 13; // 4 бита
int i_1 = 1; // 1 бит
bool b_1 = true; // 1 бит
/* Запишем значения */
BitwiseStore bitwiseStore = new BitwiseStore(size: 0);
bitwiseStore.addInt(i_12, 12);
bitwiseStore.addInt(i_6, 6);
bitwiseStore.addInt(i_4, 4);
bitwiseStore.addInt(i_1, 1);
bitwiseStore.addBool(b_1);
/* Восстановим значения */
i_12 = bitwiseStore.getInt(0, 12);
i_6 = bitwiseStore.getInt(12, 6);
i_4 = bitwiseStore.getInt(18, 4);
i_1 = bitwiseStore.getInt(22);
b_1 = bitwiseStore.getBool(23);
/* Вывод */
print('''
+-------------------------
| Исходные данные: $i_12, $i_6, $i_4, $i_1, $b_1
| Восстановленные данные: $i_12, $i_6, $i_4, $i_1, $b_1
| Хранилище: ${bitwiseStore.toString()}
| Размер хранилища: ${bitwiseStore.sizeInBytes} байт.
| Хранилище набором байт: ${bitwiseStore.toByteList()}
| Хранилище бит строкой: ${bitwiseStore.toBinary()}
| Хранилище в HEX: 0x${bitwiseStore.toHex()}
| Человекопонятное представление: ${bitwiseStore.toNiceString()}
+-------------------------
''');
}
/// Класс представляющий собой битовое хранилище данных.
///
/// !!! Внимание. Класс рассчитан на хранение до 6 байт (48 бит) !!!
///
/// Оперирует парой Хранилище и Размерность ([store] & [size]).
///
/// Хранилище отвечает за хранение данных.
/// Размерность указывает на занимаемое место.
///
/// При использовании маски [mask] выключенное состояние
/// нужно указывать с помощью '0'
/// включенное состояние - любой другой символ, желательно 'X'
///
/// Таблица размеров:
/// Что | Бит
/// ---------+------
/// bool | 1
/// 0..1 | 1
/// 2..3 | 2
/// 4..7 | 3
/// 8..15 | 4
/// 16..31 | 5
/// 32..63 | 6
/// 64..127 | 7
/// 128..255 | 8
///
class BitwiseStore {
/* Переменные */
int _store = 0x0; // Хранилище в байтах
int _size = 8; // Размерность хранилища
/* Геттеры */
int get store => getStore();
int get size => getSize();
String get storeAsString => getStoreAsString();
String get sizeAsString => getSizeAsString();
String get storeAsHes => toHex();
int get sizeInBytes => (this._size/8).ceil();
/* Константы */
static const _niceAlphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@#';
/* Конструкторы */
/// По умолчанию пустое хранилище, размером 1 байт (8 бит).
BitwiseStore({int size = 8})
: this._size = size.abs();
/// Хранилище из набора бит, обязательно указать размерность.
///
/// [initStore] 0xff - XXXXXXXX
///
/// [size] 8 - 1 байт
BitwiseStore.fromBits(int initStore, int size)
: this._store = initStore, this._size = size.abs();
/// Создать хранилище по его представлению
///
/// [mask] XXXX0000 - 0x0F, размерностью 8 бит.
BitwiseStore.fromMask(String mask)
: this._store = createBitsWithString(mask), this._size = mask.length;
/// Создать хранилище из UTF-8 строки [text]
BitwiseStore.fromUTF8(String text) {
List<int> bytes = text.codeUnits;
this._store = 0;
this._size = bytes.length*8;
for (int idx = 0; idx < bytes.length; idx++)
this._store += bytes[idx] << idx*8;
}
/// Создать хранилище из списка байт [bytes].
BitwiseStore.fromByteList(List<int> bytes) {
this._store = 0;
this._size = bytes.length*8;
for (int idx = 0; idx < bytes.length; idx++)
this._store += bytes[idx] << idx*8;
}
/// Из человекопонятной строки
BitwiseStore.fromNiceString(String niceString) {
niceString = niceString.replaceAll(r'-', '').trim();
this._size = niceString.length*6;
this._store = 0;
for (int idx = 0; idx < niceString.length; idx++)
this._store += _niceAlphabet.indexOf(niceString[idx]) << idx*6;
}
/// Создать новое хранилище из диапозона текущего
///
/// Индекс [index] и протяженность [length]
BitwiseStore slice(int index, [int length = 1]) =>
BitwiseStore.fromBits(this.getInt(index, length), length);
/* Независимые функции */
/// Побитовая запись формируется с помощью строки
///
/// Например:
///
/// 00000000 = 0 (0x00)
/// XXXXXXXX = 255 (0xFF)
/// XXXX0000 = 15 (0x0F)
static int createBitsWithString(String mask) =>
mask
.codeUnits
.asMap()
.map<int, int>((int idx, int val) => MapEntry(idx, (val == 48 ? 0 : 1) << idx))
.values
.fold(0x0, (int store, int val) => store | val);
/// Получает биты в виде строки записаной с помощью '0' и 'X'
///
/// Желательно указать размер хранилища [storeSize]
static String createStringFromBits(int bits, {int storeSize = 8, bool withDelimiter = false}) =>
List<String>(storeSize)
.asMap()
.map<int, String>((int idx, String val) => MapEntry(idx, ((bits & (1 << idx)) == 0)
? withDelimiter && idx%8==0 && idx>0 ? '-0' : '0'
: withDelimiter && idx%8==0 && idx>0 ? '-X' : 'X'))
.values
.join();
/// Создает побитовый диапозон по индексу [index] и протяженности [length]
static int createBitsRangeWithIndex(int index, [int length = 1]) =>
((1 << index) - 1) ^ ((1 << (index+length)) - 1);
/* Функции геттеры */
/// Получить содержимое хранилища
int getStore() => this._store;
/// Получить отведенный размер хранилища
int getSize() => this._size;
/// Получить полностью заполненное хранилище
int getFilledStore() => (1<<this.store)-1;
/// Получить строковое представление хранилища
String getStoreAsString() => createStringFromBits(this.store, storeSize: this._size);
/// Получить строковое представление размерности хранилища
String getSizeAsString() => ''.padRight(this._size, 'X');
/// Получить булево по индексу [index]
bool getBool(int index) => (this._store >> index) & 1 == 0 ? false : true;
/// Получить целое число по индексу [index] и протяженности [length]
int getInt(int index, [int length = 1]) =>
((((1<<index)-1)^((1<<(index+length))-1))&this._store)>>index;
/// Получает биты с помощью маски [mask].
/// Логическое 'И'
///
/// Например:
/// Данные X0X00X00 | 37
/// Маска 0000XX00 | 48
/// _________|___
/// Результат 00000X00 | 32
int getBitsWithMask(String mask) =>
this._store & createBitsWithString(mask);
/// Получает биты с помощью индекса [index] и протяженности [length]
int getBitsWithIndex(int index, [int length = 1]) =>
(((1<<index)-1)^((1<<(index+length))-1))&this._store;
/* Изменение состояния хранилища */
/// Добавляет булево [value] в конец
/// и увеличивает размерность хранилища на 1 бит
void addBool(bool value) {
this._store += value ? 1 << this._size : 0;
this._size++;
}
/// Заменяет данные [value] булевого типа (1 бит) по индексу [index] на указаные
void insertBoolWithPosition(bool value, int index) {
if (index == null)
throw Exception('Не передана позиция для вставки значения.');
else if (index + 1 > this._size)
throw Exception('Переданый индекс $index выходит за границы размеров хранилища.');
if (value)
this._store = this._store | (1 << index);
else
this._store = this._store & ~(1 << index);
}
/// Добавляет целое число [value] в конец
/// и увеличивает размерность хранилища на [length] бит
void addInt(int value, int length) {
if (value.bitLength > length)
throw Exception('Размер переданых данных больше указаного для них хранилища.');
this._store += value << this._size;
this._size += length;
}
/// Заменяет целочисленные данные ([length] бит) по индексу [index]
void insertIntWithPosition(int value, int length, int index) {
if (index == null)
throw Exception('Не передана позиция для вставки значения.');
else if (value.bitLength > length)
throw Exception('Размер переданых данных больше указаного для них хранилища.');
else if (index + length > this._size)
throw Exception('Переданый индекс $index и длина данных $length выходит за границы размеров хранилища.');
this._store = this._store & ~createBitsRangeWithIndex(index, length);
this._store = this._store | (value << index);
}
/// Устанавливает значение по индексу [index] и протяженности [length]
void setWithIndex(int index, [int length = 1]) =>
this._store = this._store | ((1 << index) - 1) ^ ((1 << (index+length)) - 1);
/// Снимает значение по индексу [index] и протяженности [length]
void unsetWithIndex(int index, [int length = 1]) =>
this._store = this._store & ~((1 << index) - 1) ^ ((1 << (index+length)) - 1);
/// Инвертирует значение по индексу [index] и протяженности [length]
void toggleWithIndex(int index, [int length = 1]) =>
this._store = this._store ^ ((1 << index) - 1) ^ ((1 << (index+length)) - 1);
/// Устанавливает значения по маске [mask]
void setWithMask(String mask) =>
this._store = this._store ^ createBitsWithString(mask);
/// Снимает значения по маске [mask]
void unsetWithMask(String mask) =>
this._store = this._store & ~createBitsWithString(mask);
/// Инвертирует значения по маске [mask]
void toggleWithMask(String mask) =>
this._store = this._store ^ createBitsWithString(mask);
/* Перегрузка операторов */
/// И
///
/// Возвращает объект BitwiseStore
BitwiseStore operator &(BitwiseStore obj) =>
BitwiseStore.fromBits(this._store & obj.store, this._size > obj.size ? this._size : obj.size);
/// ИЛИ
///
/// Возвращает объект BitwiseStore
BitwiseStore operator |(BitwiseStore obj) =>
BitwiseStore.fromBits(this._store | obj.store, this._size > obj.size ? this._size : obj.size);
/// Исключающее ИЛИ
///
/// Возвращает объект BitwiseStore
BitwiseStore operator ^(BitwiseStore obj) =>
BitwiseStore.fromBits(this._store ^ obj.store, this._size > obj.size ? this._size : obj.size);
/// Снять значение по индексу [index]
///
/// Возвращает объект BitwiseStore
BitwiseStore operator -(int index) =>
BitwiseStore.fromBits(this._store & ~(1<<index), this._size);
/// Добавить значение по индексу [index]
///
/// Возвращает объект BitwiseStore
BitwiseStore operator +(int index) =>
BitwiseStore.fromBits(this._store & 1<<index, this._size);
/// Инвертировать значение
///
/// Возвращает объект BitwiseStore
BitwiseStore operator ~() =>
BitwiseStore.fromBits(~this._store, this._size);
/// Смещение влево (увеличить на [value] разрядов)
///
/// Возвращает объект BitwiseStore
BitwiseStore operator <<(int value) =>
BitwiseStore.fromBits(this._store << value, this._size+value);
/// Смещение вправо (уменьшить на [value] разрядов)
///
/// Возвращает объект BitwiseStore
BitwiseStore operator >>(int value) =>
BitwiseStore.fromBits(this._store >> value, this._size-value);
/// Получить признак установленности [bool] бита по индексу [index]
bool operator [](int index) => this.getBool(index);
/// Сравнивает объекты [BitwiseStore] по хранилищу [store] и размерности [size]
@override
bool operator ==(dynamic obj) =>
obj != null && obj is BitwiseStore
? this._store == obj.store && this._size == obj.size
: false;
/* Вывод */
/// В бинарную строку
String toBinary() {
String binary = this._store.toRadixString(2).padLeft(this._size, '0');
return binary.substring(binary.length-this._size);
}
/// В список булево
List<bool> toBoolList() =>
List<bool>(this._size)
.asMap()
.map((int idx, bool val) => MapEntry<int, bool>(idx, this[idx]))
.values
.toList();
/// В битовую маску
String toBitMask() => createStringFromBits(this.store, storeSize: this._size, withDelimiter: false);
/// В байт список
List<int> toByteList() =>
List<int>(this.sizeInBytes)
.asMap()
.map((int idx, int val) => MapEntry<int, int>(idx, this.getInt(idx*8, 8)))
.values
.toList();
/// В UTF8 строку
String toUTF8() => String.fromCharCodes(this.toByteList());
/// Данные представленные hex строкой
String toHex() {
String hex = this._store.toRadixString(16).padLeft(this.sizeInBytes*2, '0');
return hex.substring(hex.length-this.sizeInBytes*2).toUpperCase();
}
/// В человекопонятную строку
String toNiceString() {
String niceString = '';
for (int idx = 0; idx < this._size/6; idx++)
niceString += '${idx>0 && idx%5==0 ? '-' : ''}${_niceAlphabet[this.getInt(idx*6, 6)]}';
return niceString;
}
@override
String toString() => createStringFromBits(this.store, storeSize: this._size, withDelimiter: true);
@override
int get hashCode => this._store;
}
@PlugFox
Copy link
Author

PlugFox commented May 4, 2019

+-------------------------
| Исходные данные: 2235, 62, 13, 1, true
| Восстановленные данные: 2235, 62, 13, 1, true
| Хранилище: XX0XXX0X-000X0XXX-XXX0XXXX
| Размер хранилища: 3 байт.
| Хранилище набором байт: [187, 232, 247]
| Хранилище бит строкой: 111101111110100010111011
| Хранилище в HEX: 0xF7E8BB
| Человекопонятное представление: Xy@Z
+-------------------------

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment