describe decode_set(). hell.
This commit is contained in:
+111
-4
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user