PDA

Просмотр полной версии : [Урок] Использование y_stringhash



Daniel_Cortez
26.03.2014, 19:22
Здравствуйте, ув. пользователи Pro-Pawn.ru
Сегодня я расскажу вам об использовании инклуда y_stringhash. Этот инклуд предназначен для вычисления хеш-суммы из строк, причём возможно вычисление хеша на этапе компиляции скрипта.
Хеш-сумма - это результат обработки массива данных (в нашем случае - строки), который представляет собой целое число.
Как известно, операции по сравнению чисел проходят гораздо быстрее, чем сравнения строк (strcmp), поэтому, если одна и та же строка сравнивается несколько раз, strcmp можно заменить вычислением хеша и его последующим сравнением.

Пример:


Старый код:


if(strcmp(string, "Pro") == 0)
{
// ...
}
else if(strcmp(string, "Pawn") == 0)
{
// ...
}


Новый код:


switch(YHash(string, false, hash_fnv1))
{
case _I@f<Pro>:
{
// ...
}
case _I@f<Pawn>:
{
// ...
}
}


P.S.: В данном уроке используется не совсем стандартный способ, т.к. стандартный метод (YHash(str) и _I<str>) с некоторыми символами работает неправильно и часто выдаёт коллизии.

Функции инклуда:
YHash - возвращает хеш-сумму заданной строки. Рекомендуется к использованию со строками, значение которых не известно во время компиляции (например, cmdtext в OnPlayerCommandText).
Синтаксис:

YHash(str[], bool:sensitive=true, e_HASH_TYPE:type=hash_bernstein);

str - строка, хеш которой следует получить.
sensitive - чувствительность к регистру. Если параметр будет иметь значение false, хеш из строки "Pawn" будет совпадать с хешем из "PAWN", "pawn" и т.п. По умолчанию имеет значение true.
type - алгоритм хеширования. По умолчанию используется хеш "bernstein", однако с ним велика вероятность коллизий, потому рекомендуется использовать алгоритмы "fnv1" и "fnv1a".


_H - макрос для вычисления хешей из строк, значение которых известно во время компиляции. Данная версия чувствительна к регистру: _H<Pawn> и _H<pawn> дадут разные результаты.
Поскольку алгоритм "bernstein" сравнительно часто выдаёт коллизии, рекомендуются альтернативы, в которых используются алгоритмы "fnv1" и "fnv1a" - макросы _H@f и _H@a соответственно (см. пример использования в начале статьи).
Внимание! Макрос не работает с русскими буквами и многими другими символами.
Список всех разрешённых символов:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_
В данный список входят все латинские буквы, цифры, пробел и знак подчёркивания. Остальные символы использовать нельзя.

_I - то же самое, что и _H, однако результаты не чувствительны к регистру: _I<Pawn> и _I<pawn> будут совпадать.
По уже описанной выше причине, рекомендуется использовать альтернативные варианты _I@f и _I@a.


Установка:
Инклуд y_stringhash является частью библиотеки YSI.
Скачать самую последнюю версию можно здесь:

https://github.com/Misiur/YSI/archive/master.zip
Скачав архив, извлеките из него папку "pawno" в папку с вашим модом.
В самое начало скрипта ко всем инклудам добавьте:

#include <YSI\y_stringhash>
...
PROFIT :trollface:


Автор инклуда: Y_Less
Статью подготовил: Daniel_Cortez (http://pro-pawn.ru/member.php?100-Daniel_Cortez)
При написании статьи использовались примеры из статьи: http://forum.sa-mp.com/showthread.php?t=169354


Специально для Pro-Pawn.ru (http://www.pro-pawn.ru)
Копирование данной статьи на других ресурсах без разрешения автора запрещено!

Salvacore
26.03.2014, 19:27
Спасибо:3

#Vito
26.03.2014, 20:01
Пригодится, спасибо :)

Kenny_Dalglish
14.04.2014, 14:56
C:\Users\Danil\Desktop\Дани\Дани\Inspire DeathMatch [0.3z]\pawno\include\YSI/y_stringhash.inc(70) : fatal error 100: cannot read from file: "internal\y_version"

Spectrum
14.04.2014, 15:16
C:\Users\Danil\Desktop\Дани\Дани\Inspire DeathMatch [0.3z]\pawno\include\YSI/y_stringhash.inc(70) : fatal error 100: cannot read from file: "internal\y_version"

инклуд не найден в папке

Kenny_Dalglish
14.04.2014, 16:13
инклуд не найден в папке
Это я знаю. Но и где мне его взять я скачал по ссылку

A N D R E Y
14.04.2014, 20:25
Это я знаю. Но и где мне его взять я скачал по ссылку
Создайте папку YSI в папке пано и киньте туда скачанный файл и компильте, и будет счастье.

Desulaid
24.01.2020, 22:06
Думал создать тему, но один комментарий, думаю, даст однозначный ответ. Как думаешь, есть профит в использовании подобного рода мазахозма?


#include <a_samp>
#include "YSI_Coding\y_stringhash"

enum E_PLAYER_INFO {
playername,
level,
money
};

new person_info[5][E_PLAYER_INFO] = {
{_H@f<Tony>, 1, 2000},
{_H@f<Desulaid>, 5, 1200},
{_H@f<Untonyst>, 3, 70000},
{_H@f<Darge>, 2, 8000},
{_H@f<Leex>, 4, 11040}
};

#define Hash_GetPlayerMoney(%0,"%1") __Hash_GetPlayerMoney(%0,_H@f<%1>)
stock __Hash_GetPlayerMoney(const pstrict[5][E_PLAYER_INFO], name) {
for (new i; i < 10; i++) {
if (pstrict[i][playername] == name) {
return pstrict[i][money];
}
}
return -1;
}

main()
{
printf("%d", Hash_GetPlayerMoney(person_info, "Tony"));
}

Пока я нашел пару минусов (в плане организации кода):

Надо под каждый элемент "структуры" писать свою функцию, где код шаблонный. Возможно, как-нибудь можно унифицировать это, но я писал на скорую руку ради интереса, да и вряд ли мне язык это позволит сделать без извращений.
Столько будет одинаковых итераций... А если к ним приложить игроков в сети. Как вариант, я думаю, можно прикрутить это к итераторам. Возможно(!?!) даже от шаблонности можно будет избавиться.

Daniel_Cortez
25.01.2020, 01:11
Надеюсь, это была просто шутка.
Но если всё-таки нет, то разве не проще сделать проверку на уровень админки (pAdmin)? Всяко же лучше, чем хардкодить список имён, который ещё время от времени нужно обновлять.

Desulaid
25.01.2020, 10:53
Надеюсь, это была просто шутка.
Но если всё-таки нет, то разве не проще сделать проверку на уровень админки (pAdmin)? Всяко же лучше, чем хардкодить список имён, который ещё время от времени нужно обновлять.

Блин, я был пьян и не помню этого xD