Судя по коду, выход за предел буфера будет только если указать неправильный размер.
Функция работает следующим образом: в наборе инструкций AMX есть опкод "fill", который заполняет блок данных, указанный в регистре alt значением из регистра pri. Этот опкод работает очень быстро, но в нём нельзя задать размер блока динамически, только в виде константы (динамически можно только указать через регистры адрес и значение). Поэтому в данной реализации memset массив разделяется на блоки по 4096, 1024, 256, 64, 16 и 4 байта, каждый из блоков заполняется своей инструкцией fill.
По поводу оптимальности: запись в ячейки массива с помощью обычного цикла работает куда медленнее. Даже если оптимизировать такой цикл с помощью #emit и в цикле вместо счётчика использовать адрес текущей ячейки, такой цикл будет выигрывать только на небольших массивах (до 31 ячейки).
Можете взять
профайлер и проверить моё утверждение (регулируйте размер массива в PROFILER_ARRAY_SIZE):
PHP код:
/*Настройки.*/
const PROFILER_ITERATIONS_MAJOR = 1_000_000;
const PROFILER_ITERATIONS_MINOR = 10;
new const code_snippets_names[2][] =
{
{"memset by Slice"},
{"memset by Daniel_Cortez"}
};
const PROFILER_ARRAY_SIZE = 31;
stock memset(aArray[], iValue, iSize = sizeof(aArray)) {
new iAddress;
#emit LOAD.S.pri 12
#emit STOR.S.pri iAddress
iSize *= 4;
while (iSize > 0) {
if (iSize >= 4096) {
#emit LOAD.S.alt iAddress
#emit LOAD.S.pri iValue
#emit FILL 4096
iSize -= 4096;
iAddress += 4096;
} else if (iSize >= 1024) {
#emit LOAD.S.alt iAddress
#emit LOAD.S.pri iValue
#emit FILL 1024
iSize -= 1024;
iAddress += 1024;
} else if (iSize >= 256) {
#emit LOAD.S.alt iAddress
#emit LOAD.S.pri iValue
#emit FILL 256
iSize -= 256;
iAddress += 256;
} else if (iSize >= 64) {
#emit LOAD.S.alt iAddress
#emit LOAD.S.pri iValue
#emit FILL 64
iSize -= 64;
iAddress += 64;
} else if (iSize >= 16) {
#emit LOAD.S.alt iAddress
#emit LOAD.S.pri iValue
#emit FILL 16
iSize -= 16;
iAddress += 16;
} else {
#emit LOAD.S.alt iAddress
#emit LOAD.S.pri iValue
#emit FILL 4
iSize -= 4;
iAddress += 4;
}
}
#pragma unused aArray
}
memset2(array[], value, size = sizeof(array))
{
#pragma unused array
static addr, end_addr;
const cell_size = cellbits / charbits;
#emit load.s.alt array
#emit stor.alt addr
#emit load.s.pri size
#emit smul.c cell_size
#emit add
#emit stor.pri end_addr
do
{
#emit load.alt addr
#emit load.s.pri value
#emit stor.i
}
while((addr += cell_size) != end_addr);
}
#define Prerequisites();\
new array[PROFILER_ARRAY_SIZE];
#define CodeSnippet1();\
memset(array, 0);
#define CodeSnippet2();\
memset2(array, 0);
/*Конец настроек.*/
Реализация от Slice проигрывает на массивах менее 32 элементов, но всё равно выигрывает на массивах по 24 (16 + 8), 16, 12 (8 + 4) и 9 ячеек, т.к. его алгоритм оптимизирован под блоки размером со степени двойки.