Всем привет.
Сегодня хотелось бы обсудить с вами ещё один приём для оптимизации кода на Pawn, с которым сейчас мало кто знаком: упаковывание строк. Этот приём не повлияет на производительность работы сервера, но в некоторых ситуациях может здорово помочь сэкономить память.
Дело в том, что по умолчанию компилятор Pawn хранит все строки по принципу "один символ на ячейку".
В версии Pawn для SA-MP ячейка имеет размер в 4 байта, поэтому строки хранятся в четырёхбайтовой кодировке - для хранения символа используется только один байт из четырёх, а остальные три просто расходуются впустую (они всегда заполнены нулями).
PHP код:
new const unpacked_string[] = "Sample text"; // 1 ячейка на символ -> 12 ячеек -> 48 байт
Тем не менее, в Pawn есть возможность избежать подобной растраты. Строки можно хранить в упакованном формате, в котором для каждого символа отводится не целая ячейка (4 байта), а лишь 1 байт. В таком формате строки занимают примерно в 4 раза меньше памяти, чем неупакованные строки.
Чтобы строка стала упакованной, нужно всего лишь поставить перед ней восклицательный знак.
PHP код:
new const packed_string[] = !"Sample text"; // 1 байт на символ - 12 байт (48 - 12 = 36 байт сэкономлено)
Также можно делать массивы из упакованных строк (т.е. двухмерные массивы):
PHP код:
new const faction_names[6][] =
{
{!"Нет"},
{!"Полиция"},
{!"ФСБ"},
{!"Армия"},
{!"МЧС"},
{!"Мэрия"}
};
Знак "!" не является оператором, это всего лишь часть синтаксиса объявления упакованных строк, он работает только со строками, объявленными в кавычках.
Если вы хотите упаковать строку, которая уже объявлена в виде массива, то с помощью знака "!" у вас ничего не получится.
PHP код:
new const unpacked_string[] = "Sample text";
new const packed_string[] = !unpacked_string; // Ошибка
Для работы с упакованными строками есть специальные функции:
PHP код:
// Упаковывает строку source в массив dest с размером maxlength
native strpack(dest[], const source[], maxlength=sizeof dest);
// Распаковывает строку source в массив dest
native strunpack(dest[], const source[], maxlength=sizeof dest);
Следует заметить, что другие функции из string.inc умеют работать с упакованными строками.
Рассмотрим эту особенность на примере strcat:
PHP код:
native strcat(dest[], const source[], maxlength=sizeof dest);
Если строка dest упакована, а source нет, то функция будет копировать символы из source и "на лету" упаковывать их перед записью в dest.
Примерно то же самое произойдёт, если с помощью strcat добавить упакованную строку к неупакованной.
PHP код:
// Сцепляем две строки.
new str[32] = !"string1";
new unpacked_string[] = "string2";
strcat(str, unpacked_string);
// Будет выведено "string1string2".
print(str);
Кроме функций из string.inc многие функции SA-MP также "понимают" упакованные строки.
Также следует иметь в виду, что некоторые функции не поддерживают работу с упакованными строками или работают с ними не во всех случаях:
- printf, format - эти функции сделал сам Kalcor (что уже говорит о том, что в них должно быть что-то нерабочее и это что-то никогда не будет исправлено потому что "владельцы крупных серверов решают всё за него").
В этих функциях упакованные строки не поддерживаются ни в форматной строке, ни в последующих аргументах.
- fwrite - также не поддерживает упакованные строки.
- ispacked - возвращает 0, если упакованная строка начинается с символа, код которого больше 127.
Если строка, которую вы хотите упаковать, используется в одной из перечисленных выше функций, её следует оставить неупакованной.
Собственно, это всё, что я помню про упакованные строки. Если вы думаете, что я что-то забыл, или у вас просто есть вопрос, буду рад услышать вас в комментариях.
Автор: Daniel_Cortez
Копирование данной статьи на других ресурсах без разрешения автора запрещено!