Last active
June 4, 2019 16:36
-
-
Save PlugFox/13363e58a2f8a454a518444a90282825 to your computer and use it in GitHub Desktop.
Побитовое хранилище int и bool
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Побитовое хранилище 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; | |
} |
Author
PlugFox
commented
May 4, 2019
•
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment