diff --git a/Docs/set:version.md b/Docs/set:version.md index 582eade..019db87 100644 --- a/Docs/set:version.md +++ b/Docs/set:version.md @@ -167,7 +167,7 @@ bits = 00 1 00101010 - `10` для 63 2. битовая последовательность продолжает кодироваться стандартным образом -Заметим, что данным образом невозможно получить поседовательность `ZZ`, т.к. символ `Z` требует двух старших битов выставленных в `11` +Заметим, что данным образом невозможно получить поседовательность `ZZ`, т.к. символ `Z` требует двух старших бит выставленных в `11` Пример преобразования: @@ -188,7 +188,7 @@ bits = 101111 001000 10 101111 = 1*1 + 0*2 + 1*4 + 1*8 + 1*16 + 1*32 = 61 = Z ``` -Тогда в последовательность добавляется два бита `00` сразу после битов, кодирующих Z. +Тогда в последовательность добавляется два бита `00` сразу после бит, кодирующих Z. ``` bits = 101111 000010 0010 @@ -238,6 +238,111 @@ set-строка ### `decode_set()` +Под `if(0)` в функции `decode_set()` описано интуитивное преобразование с помощью функций `decode_base62()`, `decode_golomb()` и `decode_delta()`. + +На деле же используется оптимизированный вариант из `decode_base62_golomb()` и `decode_delta()`, благодаря которым set-строка сразу преобразуется в массив `delta` значений и после восстанавливается до массива хэшей. + +### `decode_base62_golomb()` + +`decode_base62_golomb()` - оптимизированная версия стадий `decode_base62` и `decode_golomb`. Функция считывает сразу по два байта, пользуясь таблицей `word_to_num` преобразовывает их в битовую последовательность, после, набирая до 24х байт, декодирует по Rice-Golomb. + +#### `enum` + +> `enum` - word types (when two bytes from base62 string cast to unsigned short). + +В коде используется `enum` для обозначения особых случаев при считывании символов: + +```c +enum { + W_AA = 0x0000, // два обычных символа (явно не используется) + W_AZ = 0x1000, // обычный символ + Z + W_ZA = 0x2000, // Z + обычный символ + W_A0 = 0x3000, // обычный символ + конец строки + W_0X = 0x4000, // конец строки + W_EE = 0xeeee, // невозможная ситуация +}; +``` + +#### `CCI` macros + +`CCI` - макрос, объединяющий два символа в индекс таблицы `word_to_num`, с учётом порядка байтов + +#### `word_to_num[]` + +```c +static const unsigned short word_to_num[65536]; +``` + +pre-compiled таблица соответствия любой комбинации из двух байт, битовому представлению из 12 символов + возможный флаг + +Таблица строится следующим образом: + +1. все значения заполняются `W_EE` как ошибоные +2. с помощью макроса `AA1` строятся макросы `AA1x2`, `AA1x25` и т.д. вплоть до `AA10x10` и ему аналогичных. + - итоговые макросы позволяют быстро заполнить таблицу значениями `[CCI(c1, c2)] = (c1 - b1) | ((c2 - b2) << 6)` + +3. аналогичный процесс заполнения для `AZ`, но с добавлением флага `W_AZ` к значениям в таблице. +4. заполняется таблица для `ZA` значений с флагом `W_ZA`. Невозможности старших бит `11` во втором символе (т.е. символы с 48 номера) проверяется лишь внутри функций, `W_EE` для таких значений не возвращается +5. заполняется таблица для `A0` и `0X` значений с флагами `W_A0` и `W_0X` соответственно. + +#### Считывание + +Функция считывает с помощью макросов `GetXX` несколько бит (стандартно блоками до 24х бит) и передаёт их на декодирование + +при 24 битах: + +- берутся именно 4 base62-символа (по два пары) +- значение помещается в 32-битный `unsigned` +- при ограничении `Mshift >= 7` в одну последовательность может поместиться максимум 3 закодированных golomb числа. + +"12 бит" считыватель используется в ситуациях, когда первая пара обычная, а вторая содержит специальный случай + +"10 бит" считыватель используется в ситуциях с Z-escape + +"6 бит" считыватель используется для одного символа. + +#### Rice-Golomb декодер + +Декодер постоянно находится в двух состояних: + +- `q-state`: ищет unary-префикс и разделительную `1` +- `r-state`: добирает Mshift бит остатка `r` + +декодированное число восстанавливается как + +```c +value = (q << Mshift) | r; +``` + +#### Обработка Z-escape + +Для обработки Z-escape используются макросы `Esc1` и `Esc2`. + +`Esc1` вызывается при обнаружении `Z` символа и считывает старшие 2 бита у следующего символа. В результате `Esc1` получит 10 бит для golumb-декодера + +`Esc2` вызывается после завершения escape-пары и решает что делать дальше: + +- обычный символ — обработать 6 бит +- конец строки — завершить декодирование +- недопустимый символ — вернуть ошибку +- новый `Z` — снова перейти в `Esc1` + +#### `QMake` и `RMake` макросы + +`QMake` ищет разделительную единицу в текущем блоке бит. Если блок содержит только нули, все они добавляются к q, после чего функция читает следующий блок. + +Если в блоке есть единица, используется `__builtin_ffs(bits)` для определеия позиции первого бита, разделительной для golomb-кода. Оставшиеся биты заполняют r. + +`RMake` проверяет, набралось ли `Mshift` бит остатка, записывает готовое значение + +```c +*v++ = (q << Mshift) | r; +``` + +#### Завершение строки + +Допустимо завершение строки в `q-state`, но с не более чем 5 нулями. Завершение в `r-state` невозможно, т.к. остаток длиной `Mshift` не набрался. + ### `cache_decode_set()` > `cache_decode_set()` - special decode_set version with LRU caching. @@ -271,7 +376,7 @@ unsigned hash = str[0] | (str[2] << 8) | (str[3] << 16); ### `downsample_set()` -> `downsample_set()` - Reduce a set of (bpp + 1) values to a set of bpp values +> `downsample_set()` - reduce a set of (bpp + 1) values to a set of bpp values Входной массив для работы - `v`. Итоговый массив будет доступен по указателю `w`. @@ -357,7 +462,7 @@ decode_golomb() ### `test_word_table()` -WIP +В таблице `word_to_num[65536]`, необходимой для функции `decode_base62_golomb()`, проверяет, чтобы последовательность `AA` (двух не escape-символов) была равна `(char_to_num[i] | (char_to_num[j] << 6)`. Для всех остальных ситуаций проверяется лишь значение одного из символов большее 61 `char_to_num[i] >= 61 || char_to_num[j] >= 61`. ### `test_base62_golomb()` @@ -426,3 +531,5 @@ PIVOT_SIZE странный прыжки IFLT8 и IFLT4 я бы возможно делал как c1/c2 учитывая оптимизации, возможно стоит самостоятельно менять массивы местами до начала всех операций (но проблема с кэшем возможна) + +хочу себе день, чтобы переписать это всё на English