- Joined
- Jan 31, 2012
- Messages
- 42
This class is an associative array. It is equivalent to std::map in C++ and System.Collections.Generic.Dictionary in C#. To be simple, it's an array that has any possible types as indices.
It's primary purpose is creating databases. Call speed is very high because of using binary search.
To use you should include comparison library for your types:
You can have your own structs as indices, but you must write a comparison library for it:
Here is the interface of the class:
Method ForEach calls the taken function for the each note in the dictionary.
Key and Value represent the arguments of the callback function.
Method Break stops the ForEach loop.
Method Rebuild makes all the wands of the binary tree equal length, enhacing the search.
And some examples:
Code:
It's primary purpose is creating databases. Call speed is very high because of using binary search.
To use you should include comparison library for your types:
JASS:
library_once IntegerComparison
public function less takes integer op1, integer op2 returns boolean
return op1 < op2
endfunction
public function equal takes integer op1, integer op2 returns boolean
return op1 == op2
endfunction
endlibrary
library_once RealComparison
public function less takes real op1, real op2 returns boolean
return op1 < op2
endfunction
public function equal takes real op1, real op2 returns boolean
return op1 == op2
endfunction
endlibrary
library_once HandleComparison
public function less takes handle op1, handle op2 returns boolean
return GetHandleId(op1) < GetHandleId(op2)
endfunction
public function equal takes handle op1, handle op2 returns boolean
return op1 == op2
endfunction
endlibrary
library_once StringComparison
public function less takes string op1, string op2 returns boolean
return StringHash(op1) < StringHash(op2)
endfunction
public function equal takes string op1, string op2 returns boolean
return op1 == op2
endfunction
endlibrary
//Unlikely somebody will use bools as indices, but, nevertheless... :)
/*
library_once BooleanComparison
public function less takes boolean op1, boolean op2 returns boolean
if op1 then
return false
endif
return op2
endfunction
public function equal takes boolean op1, boolean op2 returns boolean
return op1 == op2
endfunction
endlibrary
*/
JASS:
struct pair
real x
real y
endstruct
library PairComparison
public function less takes pair op1, pair op2 returns boolean
if op1.x != op2.x then
return op1.x < op2.x
endif
return op1.y < op2.y
endfunction
public function equal takes pair op1, pair op2 returns boolean
return op1.x == op2.x and op1.y == op2.y
endfunction
endlibrary
JASS:
//! textmacro DeclareDictionary takes indexator_type, value_type, funcs
struct Dictionary_$indexator_type$_$value_type$
static method Create() -> thistype
method Destroy()
method Clear()
method operator [$indexator_type$] -> $value_type$
method operator [$indexator_type$]= ($value_type$)
method operator Exists[$indexator_type$] -> boolean
method ForEach(code)
static method operator ForEachKey -> $indexator_type$
static method operator ForEachValue -> $value_type$
static method Break()
method operator Count -> integer
method Rebuild()
Key and Value represent the arguments of the callback function.
Method Break stops the ForEach loop.
Method Rebuild makes all the wands of the binary tree equal length, enhacing the search.
And some examples:
JASS:
//! runtextmacro DeclareDictionary("integer", "integer", "IntegerComparison")
globals
Dictionary_integer_integer udg_RewardDatabase
endglobals
function Trig_Reward_Actions takes nothing returns boolean
local player p = GetOwningPlayer(GetKillingUnit())
local integer gold
if IsUnitEnemy(GetTriggerUnit(), p) then
set gold = udg_RewardDatabase[GetUnitTypeId(GetTriggerUnit())]
call DisplayTextToPlayer(p, .0, .0, "|cffffff00+" + I2S(gold) + "|r")
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + gold)
endif
set p = null
return false
endfunction
debug function DisplayReward takes nothing returns nothing
debug call Trace(I2S(Dictionary_integer_integer.ForEachKey) + ": " + I2S(Dictionary_integer_integer.ForEachValue))
debug endfunction
//===========================================================================
function InitTrig_Reward takes nothing returns nothing
local trigger trig = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(trig, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
exitwhen i == 15
set i = i + 1
endloop
call TriggerAddCondition(trig, Condition(function Trig_Reward_Actions))
set trig = null
set udg_RewardDatabase = Dictionary_integer_integer.Create()
set udg_RewardDatabase['hpea'] = 10
set udg_RewardDatabase['hfoo'] = 20
set udg_RewardDatabase['hkni'] = 40
set udg_RewardDatabase['hrif'] = 25
set udg_RewardDatabase['hmtm'] = 45
set udg_RewardDatabase['hgyr'] = 45
set udg_RewardDatabase['hgry'] = 55
set udg_RewardDatabase['hmpr'] = 30
set udg_RewardDatabase['hsor'] = 30
set udg_RewardDatabase['hmtt'] = 40
set udg_RewardDatabase['hspt'] = 35
set udg_RewardDatabase['hdhw'] = 35
call udg_RewardDatabase.Rebuild()
debug call Trace("Reward: " + I2S(udg_RewardDatabase.Count))
debug call udg_RewardDatabase.ForEach(function DisplayReward)
endfunction
JASS:
//! runtextmacro DeclareDictionary("handle", "integer", "HandleComparison")
//! zinc
library TrackableTest {
constant string EF1 = "Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl";
constant string EF2 = "abilities\\weapons\\DemolisherMissile\\DemolisherMissile.mdl";
Dictionary_handle_integer Dict;
struct loc extends array { real x, y; }
function onInit() {
real x = GetRectMinX(gg_rct_Region_000), y, maxX = GetRectMaxX(gg_rct_Region_000),
minY = GetRectMinY(gg_rct_Region_000), maxY = GetRectMaxY(gg_rct_Region_000);
loc l = 0;
trigger track = CreateTrigger(), hit = CreateTrigger();
trackable t;
Dict = Dictionary_handle_integer.Create();
do {
y = minY;
do {
t = CreateTrackable("units\\human\\Peasant\\Peasant.mdl", x, y, 4.712 /*bj_PI * 1.5*/);
TriggerRegisterTrackableTrackEvent(track, t);
TriggerRegisterTrackableHitEvent(hit, t);
l.x = x;
l.y = y;
Dict[t] = l;
l = l + 1;
y = y + 70.;
} while (y <= maxY);
x = x + 70.;
} while (x <= maxX);
Dict.Rebuild();
Preload(EF1);
Preload(EF2);
TriggerAddCondition(track,
function() -> boolean {
loc l = Dict[GetTriggeringTrackable()];
DestroyEffect(AddSpecialEffect(EF1, l.x, l.y));
return false;
}
);
TriggerAddCondition(hit,
function() -> boolean {
loc l = Dict[GetTriggeringTrackable()];
DestroyEffect(AddSpecialEffect(EF2, l.x, l.y));
return false;
}
);
track = null; hit = null; t = null;
}
}
//! endzinc
JASS:
//! runtextmacro DeclareDictionary("integer", "string", "IntegerComparison")
//! runtextmacro DeclareDictionary("handle", "integer", "HandleComparison")
struct mystruct
private static Dictionary_handle_integer D
private unit caster
private unit target
private integer time
private real x
private real y
private static method Timer takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = D[t]
call DestroyEffect(AddSpecialEffect(/*
*/ "Abilities\\Spells\\NightElf\\TrueshotAura\\TrueshotAura.mdl", this.x, this.y))
if this.time == 1 then
call SetUnitX(this.target, this.x)
call SetUnitY(this.target, this.y)
call PauseTimer(t)
call DestroyTimer(t)
set D[t] = 0
call deallocate(this)
else
set this.time = this.time - 1
endif
set t = null
endmethod
static method Actions takes nothing returns nothing
local timer t = CreateTimer()
local thistype this = allocate()
set this.caster = GetTriggerUnit()
set this.target = GetSpellTargetUnit()
set this.time = 4
set this.x = GetWidgetX(this.target)
set this.y = GetWidgetY(this.target)
set D[t] = this
call TimerStart(t, 1., true, function thistype.Timer)
set t = null
endmethod
private static method onInit takes nothing returns nothing
set D = Dictionary_handle_integer.Create()
call Preload("Abilities\\Spells\\NightElf\\TrueshotAura\\TrueshotAura.mdl")
endmethod
endstruct
//===========================================================================
scope Spells initializer Init
globals
private Dictionary_integer_string Database
endglobals
private function Spell takes nothing returns boolean
local string s = Database[GetSpellAbilityId()]
if s != null then
call ExecuteFunc(s)
endif
return false
endfunction
debug private function Display takes nothing returns nothing
debug call Trace(I2S(Dictionary_integer_string.ForEachKey) + ": \"" + Dictionary_integer_string.ForEachValue + "\"")
debug endfunction
private function Init takes nothing returns nothing
local trigger trig = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(trig, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
exitwhen i == 15
set i = i + 1
endloop
call TriggerAddCondition(trig, Condition(function Spell))
set trig = null
set Database = Dictionary_integer_string.Create()
set Database['A000'] = mystruct.Actions.name
set Database['A001'] = "Trig_Spell1_Actions"
set Database['A002'] = "Trig_Spell2_Actions"
set Database['A003'] = "Trig_Spell3_Actions"
set Database['A004'] = "Trig_Spell4_Actions"
set Database['A005'] = "Trig_Spell5_Actions"
call Database.Rebuild()
static /*
*/ if DEBUG_MODE then
call Trace("Spell: " + I2S(Database.Count))
call Database.ForEach(function Display)
if Database.Exists['A006'] then
call Trace("Impossible!")
endif
endif
endfunction
endscope
JASS:
//! textmacro DeclareDictionary takes indexator_type, value_type, funcs
library_once Dictionary$indexator_type$$value_type$ uses $funcs$
private struct Node extends array
static integer Max = 0
boolean Empty
static boolean ForEach_Continue = true
static integer ForEach_Stack = -1
static $indexator_type$ array ForEach_Key
static $value_type$ array ForEach_Value
static $indexator_type$ array indexAr
static $value_type$ array valueAr
$indexator_type$ index
$value_type$ value
Node n1
Node n2
static method create takes nothing returns thistype
local thistype this = 0
loop
if this == Max then
static /*
*/ if DEBUG_MODE then
if Max > 8191 then
call DisplayTimedTextToPlayer(GetLocalPlayer(), .0, .0, 60. /*
*/ "Невозможно создать узел объекта Dictionary.")
return -1
endif
endif
set Max = Max + 1
exitwhen true
endif
exitwhen this.Empty
set this = this + 1
endloop
set this.Empty = false
set this.n1 = -1
set this.n2 = -1
return this
endmethod
method destroy takes nothing returns nothing
if n1 != -1 then
call n1.destroy()
endif
if n2 != -1 then
call n2.destroy()
endif
set Empty = true
endmethod
method count takes nothing returns integer
local integer i = 0
if n1 != -1 then
set i = n1.count()
endif
if value != thistype(-1).value then
set i = i + 1
endif
if n2 != -1 then
return i + n2.count()
endif
return i
endmethod
method to_array takes integer n returns integer
if n1 != -1 then
set n = n1.to_array(n)
endif
if value != thistype(-1).value then
set indexAr[n] = index
set valueAr[n] = value
set n = n + 1
endif
set Empty = true
if n2 != -1 then
return n2.to_array(n)
endif
return n
endmethod
static method from_array takes integer n, integer jump, integer min, integer max returns thistype
local thistype this = create()
if n - jump >= min then
set this.n1 = from_array(n - jump, (jump + 1) / 2, min, n)
endif
set this.index = indexAr[n]
set this.value = valueAr[n]
if n + jump < max then
set this.n2 = from_array(n + jump, (jump + 1) / 2, n + 1, max)
endif
return this
endmethod
method for_each takes code c returns nothing
if n1 != -1 then
call n1.for_each(c)
endif
if ForEach_Continue and value != thistype(-1).value then
set ForEach_Stack = ForEach_Stack + 1
set ForEach_Key[ForEach_Stack] = index
set ForEach_Value[ForEach_Stack] = value
call ForForce(bj_FORCE_PLAYER[15], c)
set ForEach_Stack = ForEach_Stack - 1
endif
if ForEach_Continue and n2 != -1 then
call n2.for_each(c)
endif
endmethod
endstruct
private struct ExistsStruct extends array
method operator [] takes $indexator_type$ index returns boolean
if this != -1 then
loop
if $funcs$_equal(index, Node(this).index) then
return true
elseif $funcs$_less(index, Node(this).index) then
if Node(this).n1 == -1 then
return false
endif
set this = Node(this).n1
elseif Node(this).n2 == -1 then
return false
else
set this = Node(this).n2
endif
endloop
endif
return false
endmethod
endstruct
struct Dictionary_$indexator_type$_$value_type$ extends array
private static integer Max = 1
private boolean Empty
private Node root
static method Create takes nothing returns thistype
local thistype this = 1
loop
if this == Max then
if Max > 8191 then
static /*
*/ if DEBUG_MODE then
call DisplayTextToPlayer(GetLocalPlayer(), .0, .0, /*
*/ "Невозможно создать узел объекта Dictionary.")
endif
return 0
endif
set Max = Max + 1
exitwhen true
endif
exitwhen this.Empty
set this = this + 1
endloop
set this.Empty = false
set this.root = -1
return this
endmethod
method Destroy takes nothing returns nothing
if root != -1 then
call root.destroy()
endif
set Empty = true
endmethod
method operator [] takes $indexator_type$ index returns $value_type$
local Node n = root
if n != -1 then
loop
if $funcs$_equal(index, n.index) then
return n.value
elseif $funcs$_less(index, n.index) then
if n.n1 == 0 then
return Node(-1).value
endif
set n = n.n1
elseif n.n2 == 0 then
return Node(-1).value
else
set n = n.n2
endif
endloop
endif
return Node(-1).value
endmethod
method operator []= takes $indexator_type$ index, $value_type$ value returns nothing
local integer i = 0
local Node n = root
local Node array parent
if n == -1 then
if value != Node(-1).value then
set root = Node.create()
set root.index = index
set root.value = value
endif
else
set parent[0] = n
loop
if $funcs$_equal(index, n.index) then
if value == Node(-1).value and n.n1 == -1 and n.n2 == -1 then
set n.Empty = true
loop
if i == 0 then
set root = -1
return
elseif n == parent[i].n1 then
set parent[i].n1 = -1
else
set parent[i].n2 = -1
endif
exitwhen parent[i].n1 != -1 or parent[i].n2 != -1
set parent[i].Empty = true
set n = parent[i]
set i = i - 1
endloop
else
set n.value = value
endif
return
elseif $funcs$_less(index, n.index) then
if n.n1 == -1 then
if value != Node(-1).value then
set n.n1 = Node.create()
set n.n1.index = index
set n.n1.value = value
endif
return
endif
set i = i + 1
set parent[i] = n
set n = n.n1
elseif n.n2 == -1 then
if value != Node(-1).value then
set n.n2 = Node.create()
set n.n2.index = index
set n.n2.value = value
endif
return
else
set i = i + 1
set parent[i] = n
set n = n.n2
endif
endloop
endif
endmethod
method Clear takes nothing returns nothing
if root != -1 then
call root.destroy()
set root = -1
endif
endmethod
method operator Count takes nothing returns integer
if root == -1 then
return 0
endif
return root.count()
endmethod
method operator Exists takes nothing returns ExistsStruct
return root
endmethod
method ForEach takes code c returns nothing
if root != -1 then
call root.for_each(c)
set Node.ForEach_Continue = true
endif
endmethod
static method operator ForEachKey takes nothing returns $indexator_type$
return Node.ForEach_Key[Node.ForEach_Stack]
endmethod
static method operator ForEachValue takes nothing returns $value_type$
return Node.ForEach_Value[Node.ForEach_Stack]
endmethod
static method Break takes nothing returns nothing
set Node.ForEach_Continue = false
endmethod
method Rebuild takes nothing returns nothing
local integer size
if root != -1 then
set size = root.to_array(0)
set root = Node.from_array((size - 1) / 2, (size - size / 2 + 1) / 2, 0, size)
endif
endmethod
endstruct
endlibrary
//! endtextmacro
Last edited: