fix spelling
This commit is contained in:
+32
-32
@@ -45,7 +45,7 @@ struct set *set_free(struct set *set);
|
|||||||
### `set_new()`
|
### `set_new()`
|
||||||
|
|
||||||
Создаёт пустой объект `struct set` — контейнер для строк символов и их будущих hash-значений.
|
Создаёт пустой объект `struct set` — контейнер для строк символов и их будущих hash-значений.
|
||||||
Из релизации:
|
Из реализации:
|
||||||
|
|
||||||
> internally struct set is just a bag of strings and their hash values.
|
> internally struct set is just a bag of strings and their hash values.
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ set_add(s, "malloc@@GLIBC_2.2.5");
|
|||||||
|
|
||||||
```
|
```
|
||||||
массив строк
|
массив строк
|
||||||
| (Jenkins OATT)
|
| (Jenkins OAAT)
|
||||||
v
|
v
|
||||||
массив хэшей
|
массив хэшей
|
||||||
| (qsort)
|
| (qsort)
|
||||||
@@ -100,7 +100,7 @@ set-строка
|
|||||||
|
|
||||||
### hash
|
### hash
|
||||||
|
|
||||||
Для каждого элемента (строки) высчитывается 32-битный хэш и обрезается до `bpp` младщих бит
|
Для каждого элемента (строки) высчитывается 32-битный хэш и обрезается до `bpp` младших бит
|
||||||
|
|
||||||
```c
|
```c
|
||||||
unsigned mask = (1u << bpp) - 1;
|
unsigned mask = (1u << bpp) - 1;
|
||||||
@@ -109,7 +109,7 @@ set->sv[i].v = hash(set->sv[i].s) & mask;
|
|||||||
|
|
||||||
В качестве хэш-функции используется `Jenkins OAAT`.
|
В качестве хэш-функции используется `Jenkins OAAT`.
|
||||||
|
|
||||||
Получившийся массив сортируется по хэш значениям по возрастанию. При коллизии, печатается `warning: hash collision` в `stderr`
|
Получившийся массив сортируется по хэш-значениям по возрастанию. При коллизии печатается `warning: hash collision` в `stderr`
|
||||||
|
|
||||||
С помощью функции `uniqv()` в массиве остаются только уникальные значения, возвращаемое значение - размер массива после удаления повторов.
|
С помощью функции `uniqv()` в массиве остаются только уникальные значения, возвращаемое значение - размер массива после удаления повторов.
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ unsigned *v = {1, 3, 12, 8};
|
|||||||
|
|
||||||
> `encode_golomb()` - main golomb encoding routine: package integers into bits.
|
> `encode_golomb()` - main golomb encoding routine: package integers into bits.
|
||||||
|
|
||||||
Для сокращения длины итоговой строки применяется Rice-Golomb кодирование, которое позволяет с параметром `Mshift` записать число `n` как `n >> Mshift`, записанный последовательностью нулей и `n & 2^Mshift` записанный стандартным двоичным кодированием. Целая часть и остаток разделяется единичном битом.
|
Для сокращения длины итоговой строки применяется Rice-Golomb кодирование, которое позволяет с параметром `Mshift` записать число `n` как `n >> Mshift`, записанный последовательностью нулей, и `n & 2^Mshift`, записанный стандартным двоичным кодированием. Целая часть и остаток разделяются единичным битом.
|
||||||
|
|
||||||
`Mshift` выбирается как `bpp - log2(c) - 1`, т.к. при равномерном распределении `c` хэшей по диапазону `2^bpp`, средняя `delta` будет равна `2^bpp / c`
|
`Mshift` выбирается как `bpp - log2(c) - 1`, т.к. при равномерном распределении `c` хэшей по диапазону `2^bpp`, средняя `delta` будет равна `2^bpp / c`
|
||||||
|
|
||||||
@@ -161,13 +161,13 @@ bits = 00 1 00101010
|
|||||||
|
|
||||||
Алфавитом для кодирования является `0-9,a-z,A-Z`, но символ `Z` кодирует сразу 61, 62 и 63 следующим образом:
|
Алфавитом для кодирования является `0-9,a-z,A-Z`, но символ `Z` кодирует сразу 61, 62 и 63 следующим образом:
|
||||||
|
|
||||||
1. в битовую последовательность после кодированием `Z` добавляется 2 бита:
|
1. в битовую последовательность после кодирования `Z` добавляется 2 бита:
|
||||||
- `00` для 61
|
- `00` для 61
|
||||||
- `01` для 62
|
- `01` для 62
|
||||||
- `10` для 63
|
- `10` для 63
|
||||||
2. битовая последовательность продолжает кодироваться стандартным образом
|
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
|
101111 = 1*1 + 0*2 + 1*4 + 1*8 + 1*16 + 1*32 = 61 = Z
|
||||||
```
|
```
|
||||||
|
|
||||||
Тогда в последовательность добавляется два бита `00` сразу после бит, кодирующих Z.
|
Тогда в последовательность добавляется два бита `00` сразу после битов, кодирующих Z.
|
||||||
|
|
||||||
```
|
```
|
||||||
bits = 101111 000010 0010
|
bits = 101111 000010 0010
|
||||||
@@ -204,7 +204,7 @@ bits = 101111 000010 0010
|
|||||||
|
|
||||||
## Сравнение set-строк
|
## Сравнение set-строк
|
||||||
|
|
||||||
При сравнении set-строк происходит обратный процесс преобразования до получений хэш-значений
|
При сравнении set-строк происходит обратный процесс преобразования до получения хэш-значений
|
||||||
|
|
||||||
```
|
```
|
||||||
set-строка
|
set-строка
|
||||||
@@ -229,7 +229,7 @@ set-строка
|
|||||||
4. для каждого массива хэшей (`v1` и `v2`) создаётся два буферных массива `v(1|2)buf(A|B)` для функции `downsample_set()`
|
4. для каждого массива хэшей (`v1` и `v2`) создаётся два буферных массива `v(1|2)buf(A|B)` для функции `downsample_set()`
|
||||||
5. С помощью функции `downsample_set()` `bpp` обоих хэшей выравнивается до минимального из `bpp1` и `bpp2`.
|
5. С помощью функции `downsample_set()` `bpp` обоих хэшей выравнивается до минимального из `bpp1` и `bpp2`.
|
||||||
6. Создаётся два флага `ge` и `le`, для определения вложенности множеств
|
6. Создаётся два флага `ge` и `le`, для определения вложенности множеств
|
||||||
7. Вложенность множеств проверяется с помощью 3х макросов: `IFGE` `IFLT4` `IFLT8`
|
7. Вложенность множеств проверяется с помощью трёх макросов: `IFGE` `IFLT4` `IFLT8`
|
||||||
8. Возвращается значение в зависимости от вложенности:
|
8. Возвращается значение в зависимости от вложенности:
|
||||||
- 1: set1 > set2
|
- 1: set1 > set2
|
||||||
- 0: set1 == set2
|
- 0: set1 == set2
|
||||||
@@ -244,7 +244,7 @@ set-строка
|
|||||||
|
|
||||||
### `decode_base62_golomb()`
|
### `decode_base62_golomb()`
|
||||||
|
|
||||||
`decode_base62_golomb()` - оптимизированная версия стадий `decode_base62` и `decode_golomb`. Функция считывает сразу по два байта, пользуясь таблицей `word_to_num` преобразовывает их в битовую последовательность, после, набирая до 24х байт, декодирует по Rice-Golomb.
|
`decode_base62_golomb()` - оптимизированная версия стадий `decode_base62` и `decode_golomb`. Функция считывает сразу по два байта, с помощью таблицы `word_to_num` преобразует их в битовую последовательность, затем, набирая до 24 бит, декодирует по Rice-Golomb.
|
||||||
|
|
||||||
#### `enum`
|
#### `enum`
|
||||||
|
|
||||||
@@ -273,37 +273,37 @@ enum {
|
|||||||
static const unsigned short word_to_num[65536];
|
static const unsigned short word_to_num[65536];
|
||||||
```
|
```
|
||||||
|
|
||||||
pre-compiled таблица соответствия любой комбинации из двух байт, битовому представлению из 12 символов + возможный флаг
|
Предварительно скомпилированная таблица соответствия любой комбинации из двух байт с битовым представлением из 12 бит + возможный флаг
|
||||||
|
|
||||||
Таблица строится следующим образом:
|
Таблица строится следующим образом:
|
||||||
|
|
||||||
1. все значения заполняются `W_EE` как ошибоные
|
1. все значения заполняются `W_EE` как ошибочные
|
||||||
2. с помощью макроса `AA1` строятся макросы `AA1x2`, `AA1x25` и т.д. вплоть до `AA10x10` и ему аналогичных.
|
2. с помощью макроса `AA1` строятся макросы `AA1x2`, `AA1x25` и т.д. вплоть до `AA10x10` и ему аналогичных.
|
||||||
- итоговые макросы позволяют быстро заполнить таблицу значениями `[CCI(c1, c2)] = (c1 - b1) | ((c2 - b2) << 6)`
|
- итоговые макросы позволяют быстро заполнить таблицу значениями `[CCI(c1, c2)] = (c1 - b1) | ((c2 - b2) << 6)`
|
||||||
|
|
||||||
3. аналогичный процесс заполнения для `AZ`, но с добавлением флага `W_AZ` к значениям в таблице.
|
3. аналогичный процесс заполнения для `AZ`, но с добавлением флага `W_AZ` к значениям в таблице.
|
||||||
4. заполняется таблица для `ZA` значений с флагом `W_ZA`. Невозможности старших бит `11` во втором символе (т.е. символы с 48 номера) проверяется лишь внутри функций, `W_EE` для таких значений не возвращается
|
4. заполняется таблица для `ZA` значений с флагом `W_ZA`. Недопустимость старших бит `11` во втором символе (т.е. символы со значения 48) проверяется лишь внутри функций, `W_EE` для таких значений не возвращается
|
||||||
5. заполняется таблица для `A0` и `0X` значений с флагами `W_A0` и `W_0X` соответственно.
|
5. заполняется таблица для `A0` и `0X` значений с флагами `W_A0` и `W_0X` соответственно.
|
||||||
|
|
||||||
#### Считывание
|
#### Считывание
|
||||||
|
|
||||||
Функция считывает с помощью макросов `GetXX` несколько бит (стандартно блоками до 24х бит) и передаёт их на декодирование
|
Функция считывает с помощью макросов `GetXX` несколько бит (стандартно блоками до 24 бит) и передаёт их на декодирование
|
||||||
|
|
||||||
при 24 битах:
|
при 24 битах:
|
||||||
|
|
||||||
- берутся именно 4 base62-символа (по два пары)
|
- берутся именно 4 base62-символа (две пары)
|
||||||
- значение помещается в 32-битный `unsigned`
|
- значение помещается в 32-битный `unsigned`
|
||||||
- при ограничении `Mshift >= 7` в одну последовательность может поместиться максимум 3 закодированных golomb числа.
|
- при ограничении `Mshift >= 7` в одну последовательность может поместиться максимум 3 закодированных Golomb-числа.
|
||||||
|
|
||||||
"12 бит" считыватель используется в ситуациях, когда первая пара обычная, а вторая содержит специальный случай
|
"12 бит" считыватель используется в ситуациях, когда первая пара обычная, а вторая содержит специальный случай
|
||||||
|
|
||||||
"10 бит" считыватель используется в ситуциях с Z-escape
|
"10 бит" считыватель используется в ситуациях с Z-escape
|
||||||
|
|
||||||
"6 бит" считыватель используется для одного символа.
|
"6 бит" считыватель используется для одного символа.
|
||||||
|
|
||||||
#### Rice-Golomb декодер
|
#### Rice-Golomb декодер
|
||||||
|
|
||||||
Декодер постоянно находится в двух состояних:
|
Декодер постоянно находится в двух состояниях:
|
||||||
|
|
||||||
- `q-state`: ищет unary-префикс и разделительную `1`
|
- `q-state`: ищет unary-префикс и разделительную `1`
|
||||||
- `r-state`: добирает Mshift бит остатка `r`
|
- `r-state`: добирает Mshift бит остатка `r`
|
||||||
@@ -318,9 +318,9 @@ value = (q << Mshift) | r;
|
|||||||
|
|
||||||
Для обработки Z-escape используются макросы `Esc1` и `Esc2`.
|
Для обработки Z-escape используются макросы `Esc1` и `Esc2`.
|
||||||
|
|
||||||
`Esc1` вызывается при обнаружении `Z` символа и считывает старшие 2 бита у следующего символа. В результате `Esc1` получит 10 бит для golumb-декодера
|
`Esc1` вызывается при обнаружении символа `Z` и считывает старшие 2 бита у следующего символа. В результате `Esc1` получает 10 бит для Golomb-декодера
|
||||||
|
|
||||||
`Esc2` вызывается после завершения escape-пары и решает что делать дальше:
|
`Esc2` вызывается после завершения escape-пары и решает, что делать дальше:
|
||||||
|
|
||||||
- обычный символ — обработать 6 бит
|
- обычный символ — обработать 6 бит
|
||||||
- конец строки — завершить декодирование
|
- конец строки — завершить декодирование
|
||||||
@@ -329,9 +329,9 @@ value = (q << Mshift) | r;
|
|||||||
|
|
||||||
#### `QMake` и `RMake` макросы
|
#### `QMake` и `RMake` макросы
|
||||||
|
|
||||||
`QMake` ищет разделительную единицу в текущем блоке бит. Если блок содержит только нули, все они добавляются к q, после чего функция читает следующий блок.
|
`QMake` ищет разделительную единицу в текущем блоке бит. Если блок содержит только нули, все они добавляются к `q`, после чего функция читает следующий блок.
|
||||||
|
|
||||||
Если в блоке есть единица, используется `__builtin_ffs(bits)` для определеия позиции первого бита, разделительной для golomb-кода. Оставшиеся биты заполняют r.
|
Если в блоке есть единица, используется `__builtin_ffs(bits)` для определения позиции первого бита, разделительной для Golomb-кода. Оставшиеся биты заполняют `r`.
|
||||||
|
|
||||||
`RMake` проверяет, набралось ли `Mshift` бит остатка, записывает готовое значение
|
`RMake` проверяет, набралось ли `Mshift` бит остатка, записывает готовое значение
|
||||||
|
|
||||||
@@ -360,7 +360,7 @@ value = (q << Mshift) | r;
|
|||||||
unsigned hash = str[0] | (str[2] << 8) | (str[3] << 16);
|
unsigned hash = str[0] | (str[2] << 8) | (str[3] << 16);
|
||||||
```
|
```
|
||||||
|
|
||||||
массивы `hv` и `ev` представляют из себя аналог LRU кэша размером `CACHE_SIZE=256`.
|
массивы `hv` и `ev` представляют собой аналог LRU-кэша размером `CACHE_SIZE=256`.
|
||||||
|
|
||||||
Если fingerprint set-строки на декодирование совпал с имеющимся в `hv` массиве, проверяется полное соответствие строки с `ev[i]->str`. В случае hit - элемент помещается на нулевую позицию, остальные элементы сдвигаются.
|
Если fingerprint set-строки на декодирование совпал с имеющимся в `hv` массиве, проверяется полное соответствие строки с `ev[i]->str`. В случае hit - элемент помещается на нулевую позицию, остальные элементы сдвигаются.
|
||||||
При неудачной проверке полной set-строки, поиск по кэшу продолжается.
|
При неудачной проверке полной set-строки, поиск по кэшу продолжается.
|
||||||
@@ -370,9 +370,9 @@ unsigned hash = str[0] | (str[2] << 8) | (str[3] << 16);
|
|||||||
- Если кэш не заполнен, декодируемая строка записывается на первую свободную позицию
|
- Если кэш не заполнен, декодируемая строка записывается на первую свободную позицию
|
||||||
- Если кэш заполнен, элемент ставится на `PIVOT_SIZE=243` позицию, элементы с этой позиции сдвигаются.
|
- Если кэш заполнен, элемент ставится на `PIVOT_SIZE=243` позицию, элементы с этой позиции сдвигаются.
|
||||||
|
|
||||||
#### `SENTINELS` биты
|
#### `SENTINELS` значения
|
||||||
|
|
||||||
Данные `~0u` биты необходимы при дальнейшем проходе по массиву внутри функции `rpmsetcmp()`, т.к. там происходят прыжки по 4 и 8 элементов.
|
Данные `~0u` значения необходимы при дальнейшем проходе по массиву внутри функции `rpmsetcmp()`, т.к. там происходят прыжки по 4 и 8 элементов.
|
||||||
|
|
||||||
### `downsample_set()`
|
### `downsample_set()`
|
||||||
|
|
||||||
@@ -382,7 +382,7 @@ unsigned hash = str[0] | (str[2] << 8) | (str[3] << 16);
|
|||||||
Итоговый массив будет доступен по указателю `w`.
|
Итоговый массив будет доступен по указателю `w`.
|
||||||
Возвращаемое значение - количество элементов в новом массиве `w`.
|
Возвращаемое значение - количество элементов в новом массиве `w`.
|
||||||
|
|
||||||
Т.к. первоначальный входной массив отсортирован, после обрезания до `bpp` бит, массив будет поделён на две части, обе из которых будут отсортированны. Деление массива будет происходить в месте, где старший бит на позции `bpp+1` становится равным `1`.
|
Т.к. первоначальный входной массив отсортирован, после обрезания до `bpp` бит массив будет поделён на две части, обе из которых будут отсортированы. Деление массива будет происходить в месте, где старший бит на позиции `bpp+1` становится равным `1`.
|
||||||
|
|
||||||
Далее обе половины массива объединяются в буфере `w`, дубликаты значений удаляются.
|
Далее обе половины массива объединяются в буфере `w`, дубликаты значений удаляются.
|
||||||
|
|
||||||
@@ -401,7 +401,7 @@ return value = 5
|
|||||||
|
|
||||||
#### Макросы `IFLT*`
|
#### Макросы `IFLT*`
|
||||||
|
|
||||||
`IFLT8` быстро продвигают `v1`, пока `*v1 < v2val`. Сперва макрос "грубо" прыгает по 8 элементов, далее уточняет с шагом 4, 2, 1.
|
`IFLT8` быстро продвигает `v1`, пока `*v1 < v2val`. Сперва макрос "грубо" прыгает по 8 элементов, далее уточняет с шагом 4, 2, 1.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
+8 +8 +8 ... // грубый поиск
|
+8 +8 +8 ... // грубый поиск
|
||||||
@@ -427,18 +427,18 @@ return value = 5
|
|||||||
|
|
||||||
То есть текущий элемент `v2val` есть во втором множестве, но отсутствует в первом.
|
То есть текущий элемент `v2val` есть во втором множестве, но отсутствует в первом.
|
||||||
|
|
||||||
Следовательно `v1` уже не может быть над множеством `v2`:
|
Следовательно `v1` уже не может быть надмножеством `v2`:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
ge = 0;
|
ge = 0;
|
||||||
v2++;
|
v2++;
|
||||||
```
|
```
|
||||||
|
|
||||||
## `SEFT_TEST` флаг
|
## `SELF_TEST` флаг
|
||||||
|
|
||||||
При выставленном `SEFT_TEST` флаге происходит следующее:
|
При выставленном `SELF_TEST` флаге происходит следующее:
|
||||||
|
|
||||||
1. Явно отклчючается `NDEBUG` для работы `assert()`
|
1. Явно отключается `NDEBUG` для работы `assert()`
|
||||||
2. Компилируются `test_*` функции
|
2. Компилируются `test_*` функции
|
||||||
3. Компилируется `main()`, запускающая все `test_*` функции
|
3. Компилируется `main()`, запускающая все `test_*` функции
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user