Здравствуйте.
Анализируя свой код подробнее, стремясь выяснить, что и как работает, хотел бы получить у уважаемых адептов 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.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
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;
}
Приведи задачу, где необходима будет именно рекурсия, я че-то не понимаю
0
4
7 лет назад
Отредактирован Singularity
0
Хеш-таблица для чего была придумана? В ней же можно хранить индекс боевой единицы, используя её хендл-идентификатор. А ещё есть Set\GetUnitUserData..., если конечно он не забронирован другой системой.
Стоит отдать хэш-таблице должное - она точно ещё тяжелее группы.
с чего вдруг рекурсивные? Обычные циклы-переборы. На Си скорость выходит такая, что любые костыли-попытки на жассе в пролете.
Собственно, моя задача в том, чтобы сделать быструю систему с максимальным взаимодействием с ядром WarCraft III, то есть плагин, а не костыль.
Вот и ищу способ.
В надежде на ответ,
Singularity, 29.06.2017
0
32
7 лет назад
0
Ну дык пиши весь код карты на асме или вовсе инжекти мемхаком дллку, на Си все будет ближе и быстрее.
9
26
7 лет назад
Отредактирован Hanabishi
9
Странное понимание механики. Не бывает универсального лучшего способа, потому и существуют разные способы для конкретных ситуаций.
А экономить байты и такты процессора, заранее пользуясь интерпретируемым скриптовым языком, это вообще моветон.
Разве массив в WarCraft III не предынициализирует 8192 ячейки памяти (по Вашей формуле, в моём случае он потребляет 8192*4=32768 байт, то есть 32Кб)? Он ведь не динамический.
Нет, он динамический. Исходный размер при создании - 1024. И расширяется на 1024 ячейки по мере доступа вплоть до максимальных 8192.
Принятый ответ
0
4
7 лет назад
Отредактирован Singularity
0
Нет, он динамический. Исходный размер при создании - 1024. И расширяется на 1024 ячейки по мере доступа вплоть до максимальных 8192.
Спасибо за пояснение, я этого не знал. То есть, сначала инициализируется 1024 ячейки, когда происходит доступ к следующим 1024-м, инициализируется ещё 1024 и это происходит до максимума в 8192, понял ли я это верно?
Мдамс, над статьёй работать ещё и работать...
Засучив рукава,
Singularity, 29.06.2017
0
30
7 лет назад
0
любую рекурсию можно превратить в цикл
Разумеется, да, только далеко не всегда целесообразно так делать.
DracoL1ch:
Ну вот из псевдокода по IsUnitInGroup
Так лол, сишные компиляторы всегда переводят хвостовую рекурсию в плоскую итерацию, ЕМНИП.

Минут через несколько вкину пример, в котором, на мой взгляд, применение рекурсии весьма оправдано.
Время программиста всегда дороже времени процессора \о/
0
26
7 лет назад
0
о есть, сначала инициализируется 1024 ячейки, когда происходит доступ к следующим 1024-м, инициализируется ещё 1024 и это происходит до максимума в 8192, понял ли я это верно?
Да.
Разумеется, да, только далеко не всегда целесообразно так делать.
Так лол, сишные компиляторы всегда переводят хвостовую рекурсию в плоскую итерацию, ЕМНИП.
Вроде как нет, от того в вещах типа быстрой сортировки и случается переполнение стека вызовов. Но в случае вара это вообще пофиг, так как ограничение на на количество операций.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.