Здравствуйте.
Анализируя свой код подробнее, стремясь выяснить, что и как работает, хотел бы получить у уважаемых адептов JASS разъяснение важного для меня вопроса о том, как две конструкции JASS обходятся с памятью.
Есть блок кода, который можно впихнуть в любую бибилотеку или область
globals
    unit array UnitIndexer // Конечно, даже по меркам vJASS, если написать UnitIndexer[размер_массива_ниже_8191], это будет синтаксический сахар, так как массивы в WarCraft III статические и меньше 8192 ячеек в памяти инициализировать не станут.
    integer Indexer_Index = 0
endglobals

function GetUnitIndex takes unit whichUnit returns integer
    // Знаю, что не самая оптимальная реализация, но задача этого кода - показать суть дела.
    local integer i = 0

    loop
        exitwhen i > Indexer_Index
        if UnitIndexer[i] == whichUnit then
            return i
        endif
        set i = i + 1
    endloop

    return -1
endfunction

function IsUnitIndexed takes unit whichUnit returns boolean
    return GetUnitIndex(whichUnit) >= 0
endfunction

function IndexNewUnit takes unit whichUnit returns nothing
    // Не стану показывать проверку на дубликаты и "защиту от дураков", чтобы не усложнять код.
    set UnitIndexer[Indexer_Index] = whichUnit
    set Indexer_Index = Indexer_Index + 1
endfunction
И есть другой блок кода - иной подход к реализации того же самого
globals
    group UnitIndexer = null
endglobals

function IsUnitIndexed takes unit whichUnit returns boolean
    return IsUnitInGroup(whichUnit,UnitIndexer)
endfunction

function IndexNewUnit takes unit whichUnit returns nothing
    if UnitIndexer == null then
        set UnitIndexer = CreateGroup()
    endif
    call GroupAddUnit(UnitIndexer,whichUnit)
endfunction
Какой способ лучше с точки зрения памяти?
С массивами - понятно, создаётся 8191 экземпляр для хранения ссылки на объект unit.
Группа видится мне динамическим массивом, который аллоцирует и деаллоцирует память по необходимости.
Расскажите мне, как на самом деле обстоит дело.
В ожидании ответа,
Singularity, 29.06.2017

Принятый ответ

Странное понимание механики. Не бывает универсального лучшего способа, потому и существуют разные способы для конкретных ситуаций.
А экономить байты и такты процессора, заранее пользуясь интерпретируемым скриптовым языком, это вообще моветон.
Разве массив в WarCraft III не предынициализирует 8192 ячейки памяти (по Вашей формуле, в моём случае он потребляет 8192*4=32768 байт, то есть 32Кб)? Он ведь не динамический.
Нет, он динамический. Исходный размер при создании - 1024. И расширяется на 1024 ячейки по мере доступа вплоть до максимальных 8192.

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
5
16
7 лет назад
5
чего ты хочешь добиться? ни один костыль не работает быстрее, чем нативка. нативки групп быстрее любого перебора на жассе. доступ к массиву чуть-чуть быстрее, чем к группе, но в 99.9% случаев вы не используете вечные таймеры с 0.02 таймаутом, чтобы это что-то решало.
если работаешь с группами - то так и работай. это связанный список с динамической линковкой юнитов, ничего в нем плохого нет. а про память волноваться следовало в 90х - сегодня +- мегабайт никто и не заметит. Ну а если прям зудит - массив это ~10 байт на служебные и максимальныйиндекс*4 под данные. Группа - ~200 байт под служебные и кол-во юнитов*4 под список
1
28
7 лет назад
1
кол-во юнитов*4 под список
если это список то по идее узлы должны хранить ссылки на соседей и должно получаться *8 или *12
0
4
7 лет назад
Отредактирован Singularity
0
DracoL1ch:
чего ты хочешь добиться? ни один костыль не работает быстрее, чем нативка. нативки групп быстрее любого перебора на жассе. доступ к массиву чуть-чуть быстрее, чем к группе, но в 99.9% случаев вы не используете вечные таймеры с 0.02 таймаутом, чтобы это что-то решало.
если работаешь с группами - то так и работай. это связанный список с динамической линковкой юнитов, ничего в нем плохого нет. а про память волноваться следовало в 90х - сегодня +- мегабайт никто и не заметит. Ну а если прям зудит - массив это ~10 байт на служебные и максимальныйиндекс*4 под данные. Группа - ~200 байт под служебные и кол-во юнитов*4 под список
Подождите, подождите. Откуда взяты цифры в 10 байт и в 200 байт?
Разве массив в WarCraft III не предынициализирует 8192 ячейки памяти (по Вашей формуле, в моём случае он потребляет 8192*4=32768 байт, то есть 32Кб)? Он ведь не динамический.
В ожидании ответа,
Singularity, 29.06.2017
0
29
7 лет назад
Отредактирован Волчачка
0
Хеш-таблица для чего была придумана? В ней же можно хранить индекс боевой единицы, используя её хендл-идентификатор. А ещё есть Set\GetUnitUserData..., если конечно он не забронирован другой системой.
1
16
7 лет назад
Отредактирован DracoL1ch
1
ай, точно, каждый линк в цепочке то ли 5, то ли 6 4-байтовых dword, там не только на соседей, но еще и контрольная какая-то инфа, не знаю, для чего, так что группа тяжелее в разы выходит
нет, массив переносится при необходимости добавить места, по умолчанию он не выделяет ничего, а когда доходит до запроса - начинает работать
цифры взяты из структуры. состав массива не знаю, но адрес начала хранится в 0xC, т.е. минимум 12 байт под начальные данные, а там хз что дальше, но немного.
группа же до 0x5C простирается, или 23 4-байтовых, глянул в своей разметке
сначала писал числа от балды по примерной памяти. эта инфа абсолютно не важна
0
29
7 лет назад
0
В чем смысл чето городить. На 1 юнита достаточно одной структуры в любой карте. Адрес структуры можно хранить в кастом велью. Единственные места где нужно пользоваться самим юнитом это там куда этот юнит приходит (ивенты) и там куда он уходит (нативки). В остальном пользуемся самой структурой.
0
30
7 лет назад
Отредактирован Clamp
0
Индексация боевых единиц при помощи массива
Очевидное преимущество в том, что юнита можно заменить на что угодно и оно будет работать как надо. Кроме того, если стак обрабатывается таймером с высоким периодом, то массив будет показывать себя заметно лучше в плане быстродействия, пруф, бенчмарк.

Если группа - это связанный список, то "под капотом" почти всех функций из Groups API используются рекурсивные алгоритмы, и чем больше в группе юнитов, тем медленнее они работают.

А код из статьи Скорпа можно было оставить и без подобной переработки.
0
16
7 лет назад
0
с чего вдруг рекурсивные? Обычные циклы-переборы. На Си скорость выходит такая, что любые костыли-попытки на жассе в пролете.
0
30
7 лет назад
0
Обычные циклы-переборы.
Хочу пример обычного цикла-перебора для связанного списка =)
0
28
7 лет назад
Отредактирован nvc123
0
Clamp, любую рекурсию можно превратить в цикл
кроме того связанный список поддерживает итераторы которые внезапно используются в циклах
вот тебе пример для списка с граничным узлом
int size(List list){
	int size=0;
	Node n=list.node(); 
	while(n.hasNext()){
		size++;
		n=n.next();
	}
}
без граничного будет тоже самое только с проверкой на пустоту и do while
0
16
7 лет назад
Отредактирован DracoL1ch
0
Ну вот из псевдокода по IsUnitInGroup:
v5 начинается с 0-го элемента списка
while ( *(_DWORD *)(v5 + 8) != a2 )
{
v5 = *(_DWORD *)(v5 + 4);
if ( v5 <= 0 )
goto LABEL_8;
}
Приведи задачу, где необходима будет именно рекурсия, я че-то не понимаю
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.