- Joined
- Jan 1, 2010
- Messages
- 197
** APPROPRIATELY RENAMED Array<T>
Disclaimer: If you're looking for the full featured, fully developed version, please use Vector<T> Developed by Bannar in conjunction with Bribe's table.
Edit: This code snippet now contains code for a Map<T, T> (currently only supports value type to value type)
This is a very simple implementation with a small amount of code. Why did I do this?
This is also for anyone just wanting a simple all-in-one solution to this problem with not dependencies on other libraries.
onto the code:
Disclaimer: If you're looking for the full featured, fully developed version, please use Vector<T> Developed by Bannar in conjunction with Bribe's table.
Edit: This code snippet now contains code for a Map<T, T> (currently only supports value type to value type)
This is a very simple implementation with a small amount of code. Why did I do this?
- Deepen my own understanding of the single hash-table philosophy
- Create a simple library that's easy to read and understand
- Allow others who are learning to study the concept themselves a bit, in a more simplified fashion.
This is also for anyone just wanting a simple all-in-one solution to this problem with not dependencies on other libraries.
onto the code:
JASS:
//not much to see here, just a function I'm using to dealloc triggers
library TriggerUtil
public function cleanTrigger takes trigger t returns nothing
call TriggerClearActions(t)
call TriggerClearActions(t)
call DestroyTrigger(t)
endfunction
endlibrary
JASS:
/*
This is for use with types integer, real, and string
DO NOT ATTEMPT TO USE THIS WITH trigger or other handle types
*/
//! textmacro mapValueType takes ACCSESSOR, KEY_TYPE_LOWER, KEY_TYPE_UPPER, HASH_FUNC, VALUE_TYPE_UPPER, VALUE_TYPE_LOWER
public struct $KEY_TYPE_UPPER$To$VALUE_TYPE_UPPER$Map
private integer tableInd
private integer values
public static method create takes nothing returns thistype
local thistype new = .allocate()
set new.tableInd = allocTable()
set new.values = 0
if new.tableInd == -1 then
call BJDebugMsg("Warning... inner hashtable allocation failed! Report this issue to the map maker. No table struct allocated...")
call new.destroy()
return -1
endif
return new
endmethod
public method operator[] takes $KEY_TYPE_LOWER$ key returns $VALUE_TYPE_LOWER$
local integer ind = $HASH_FUNC$(key)
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Map error: No value at element " + I2S(ind) + " when trying to access element, report this bug to the map maker!")
endif
return Load$ACCSESSOR$(hashtables, this.tableInd, ind)
endmethod
//DO NOT use this method for expanding the table, use push instead!
public method operator[]= takes $KEY_TYPE_LOWER$ key, $VALUE_TYPE_LOWER$ value returns nothing
local integer ind = $HASH_FUNC$(key)
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Map error: No value at element " + I2S(ind) + " when trying to mutate element, report this bug to the map maker!")
return
endif
call Save$ACCSESSOR$(hashtables, this.tableInd, ind, value)
endmethod
public method push takes $KEY_TYPE_LOWER$ key, $VALUE_TYPE_LOWER$ value returns nothing
local integer ind = $HASH_FUNC$(key)
call Save$ACCSESSOR$(hashtables, this.tableInd, ind, value)
set this.values = this.values + 1
endmethod
public method pop takes $KEY_TYPE_LOWER$ key returns nothing
local integer ind = $HASH_FUNC$(key)
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Map error: No value at element " + I2S(ind) + " when trying to pop element, report this bug to the map maker!")
return
endif
set this.values = this.values - 1
call RemoveSaved$VALUE_TYPE_UPPER$(hashtables, this.tableInd, ind)
endmethod
public method size takes nothing returns integer
return this.values
endmethod
public method hashtableIndex takes nothing returns integer
return this.tableInd
endmethod
private method hasValueAt takes integer ind returns boolean
return HaveSaved$VALUE_TYPE_UPPER$(hashtables, this.tableInd, ind)
endmethod
public method hasValueAtKey takes $KEY_TYPE_LOWER$ key returns boolean
local integer ind = $HASH_FUNC$(key)
return this.hasValueAt(ind)
endmethod
public method flush takes nothing returns nothing
call FlushChildHashtable(hashtables, this.tableInd)
set this.values = 0
endmethod
public method onDestroy takes nothing returns nothing
if deallocTable(this.tableInd) == -1 then
call BJDebugMsg("Hashtable deallocation failed! Report this issue to the map maker.")
endif
call this.flush()
endmethod
endstruct
//! endtextmacro
JASS:
/*
This is for use with types integer, real, and string
DO NOT ATTEMPT TO USE THIS WITH trigger or other handle types
*/
//! textmacro arrayValueType takes ACCSESSOR, TYPE_UPPER, TYPE_LOWER
public struct $TYPE_UPPER$Array
private integer tableInd
private integer values
public static method create takes nothing returns thistype
local thistype new = .allocate()
set new.tableInd = allocTable()
set new.values = 0
if new.tableInd == -1 then
call BJDebugMsg("Warning... inner hashtable allocation failed! Report this issue to the map maker. No table struct allocated...")
call new.destroy()
return -1
endif
return new
endmethod
public method operator[] takes integer ind returns $TYPE_LOWER$
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Array error: No value at element " + I2S(ind) + " when trying to access element, report this bug to the map maker!")
endif
return Load$ACCSESSOR$(hashtables, this.tableInd, ind)
endmethod
//DO NOT use this method for expanding the table, use push instead!
public method operator[]= takes integer ind, $TYPE_LOWER$ value returns nothing
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Array error: No value at element " + I2S(ind) + " when trying to mutate element, report this bug to the map maker!")
return
endif
call Save$ACCSESSOR$(hashtables, this.tableInd, ind, value)
endmethod
public method push takes $TYPE_LOWER$ value returns nothing
call Save$ACCSESSOR$(hashtables, this.tableInd, this.values, value)
set this.values = this.values + 1
endmethod
public method pop takes nothing returns nothing
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
return
endif
call RemoveSaved$TYPE_UPPER$(hashtables, this.tableInd, this.values - 1)
set this.values = this.values - 1
endmethod
public method top takes nothing returns $TYPE_LOWER$
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
endif
return Load$ACCSESSOR$(hashtables, this.tableInd, this.values -1)
endmethod
public method bottom takes nothing returns $TYPE_LOWER$
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
endif
return Load$ACCSESSOR$(hashtables, this.tableInd, 0)
endmethod
public method size takes nothing returns integer
return this.values
endmethod
public method hashtableIndex takes nothing returns integer
return this.tableInd
endmethod
public method hasValueAt takes integer ind returns boolean
return HaveSaved$TYPE_UPPER$(hashtables, this.tableInd, ind)
endmethod
public method flush takes nothing returns nothing
call FlushChildHashtable(hashtables, this.tableInd)
set this.values = 0
endmethod
public method onDestroy takes nothing returns nothing
if deallocTable(this.tableInd) == -1 then
call BJDebugMsg("Hashtable deallocation failed! Report this issue to the map maker.")
endif
call this.flush()
endmethod
endstruct
//! endtextmacro
JASS:
/*
This is for use with handle types like trigger
Memory, by default, is NOT managed by the table.
However, if you set wantDestroy to true,
the table will deallocate the underlying objects.
You can also use destroyTop which is a destructive version of pop
*/
//! textmacro arrayHandleType takes TYPE_UPPER, TYPE_LOWER, DEALLOC_FUNC
public struct $TYPE_UPPER$Array
private integer tableInd
private integer values
private boolean wantDestroy
public static method create takes nothing returns thistype
local thistype new = .allocate()
set new.tableInd = allocTable()
set new.values = 0
set new.wantDestroy = false
if new.tableInd == -1 then
call BJDebugMsg("Warning... inner hashtable allocation failed! Report this issue to the map maker. No table struct allocated...")
call new.destroy()
return -1
endif
return new
endmethod
public method operator[] takes integer ind returns $TYPE_LOWER$
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Array error: No value at element " + I2S(ind) + " when trying to access element, report this bug to the map maker!")
return null
endif
return Load$TYPE_UPPER$Handle(hashtables, this.tableInd, ind)
endmethod
//DO NOT use this method for expanding the table, use push instead!
public method operator[]= takes integer ind, $TYPE_LOWER$ value returns nothing
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Array error: No value at element " + I2S(ind) + " when trying to mutate element, report this bug to the map maker!")
return
endif
call Save$TYPE_UPPER$Handle(hashtables, this.tableInd, ind, value)
endmethod
public method push takes $TYPE_LOWER$ value returns nothing
call Save$TYPE_UPPER$Handle(hashtables, this.tableInd, this.values, value)
set this.values = this.values + 1
endmethod
//this method won't call the deallocation method for the underlying object
public method pop takes nothing returns nothing
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
return
endif
call RemoveSavedHandle(hashtables, this.tableInd, this.values - 1)
set this.values = this.values - 1
endmethod
//like pop, but destructive to the underlying object
public method destroyTop takes nothing returns nothing
local $TYPE_LOWER$ toDestroy
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
return
endif
set toDestroy = Load$TYPE_UPPER$Handle(hashtables, this.tableInd, this.values - 1)
call RemoveSavedHandle(hashtables, this.tableInd, this.values - 1)
call $DEALLOC_FUNC$(toDestroy)
set toDestroy = null
set this.values = this.values - 1
endmethod
/*
Destroys the element at ind and replaces it with with.
Removes the memory for the underlying object
Must be an object at element ind!
*/
public method replace takes integer ind, $TYPE_LOWER$ with returns nothing
local $TYPE_LOWER$ toDestroy
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Array error: No value at element " + I2S(ind) + " when trying to mutate element, report this bug to the map maker!")
return
endif
set toDestroy = Load$TYPE_UPPER$Handle(hashtables, this.tableInd, ind)
call Save$TYPE_UPPER$Handle(hashtables, this.tableInd, ind, with)
call $DEALLOC_FUNC$(toDestroy)
set toDestroy = null
endmethod
public method top takes nothing returns $TYPE_LOWER$
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
return null
endif
return Load$TYPE_UPPER$Handle(hashtables, this.tableInd, this.values -1)
endmethod
public method bottom takes nothing returns $TYPE_LOWER$
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
return null
endif
return Load$TYPE_UPPER$Handle(hashtables, this.tableInd, 0)
endmethod
public method size takes nothing returns integer
return this.values
endmethod
public method hashtableIndex takes nothing returns integer
return this.tableInd
endmethod
public method hasValueAt takes integer ind returns boolean
return HaveSavedHandle(hashtables, this.tableInd, ind)
endmethod
//this method will not deallocate the underlying objects
public method flush takes nothing returns nothing
call FlushChildHashtable(hashtables, this.tableInd)
set this.values = 0
endmethod
//identitcal to flush, but also destroys the underlying objects
public method cleansAll takes nothing returns nothing
loop
exitwhen this.values == 0
call this.destroyTop()
endloop
call this.flush()
endmethod
//flags wantDestroy to the desired value
//if wantDestroy is flagged, cleansAll() is called upon destruction rather than flush()
public method setWantDestroy takes boolean to returns nothing
set this.wantDestroy = to
endmethod
public method isWantDestroy takes nothing returns boolean
return this.wantDestroy
endmethod
public method onDestroy takes nothing returns nothing
if deallocTable(this.tableInd) == -1 then
call BJDebugMsg("Hashtable deallocation failed! Report this issue to the map maker.")
endif
if (this.wantDestroy) then
call this.cleansAll()
else
call this.flush()
endif
endmethod
endstruct
//! endtextmacro
JASS:
/*
This is for use with struct types
Not to be used with any other variable types, must be a struct
*/
//! textmacro arrayStructType takes TYPE
public struct $TYPE$Array
private integer tableInd
private integer values
private boolean wantDestroy
public static method create takes nothing returns thistype
local thistype new = .allocate()
set new.tableInd = allocTable()
set new.values = 0
set new.wantDestroy = false
if new.tableInd == -1 then
call BJDebugMsg("Warning... inner hashtable allocation failed! Report this issue to the map maker. No table struct allocated...")
call new.destroy()
return -1
endif
return new
endmethod
public method operator[] takes integer ind returns $TYPE$
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Array error: No value at element " + I2S(ind) + " when trying to access element, report this bug to the map maker!")
return null
endif
return LoadInteger(hashtables, this.tableInd, ind)
endmethod
//DO NOT use this method for expanding the table, use push instead!
public method operator[]= takes integer ind, $TYPE$ value returns nothing
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Array error: No value at element " + I2S(ind) + " when trying to mutate element, report this bug to the map maker!")
return
endif
call SaveInteger(hashtables, this.tableInd, ind, value)
endmethod
public method push takes $TYPE$ value returns nothing
call SaveInteger(hashtables, this.tableInd, this.values, value)
set this.values = this.values + 1
endmethod
//this method won't call the deallocation method for the underlying object
public method pop takes nothing returns nothing
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
return
endif
call RemoveSavedInteger(hashtables, this.tableInd, this.values - 1)
set this.values = this.values - 1
endmethod
//like pop, but destructive to the underlying object
public method destroyTop takes nothing returns nothing
local $TYPE$ toDestroy
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
return
endif
set toDestroy = LoadInteger(hashtables, this.tableInd, this.values - 1)
call RemoveSavedInteger(hashtables, this.tableInd, this.values - 1)
call toDestroy.destroy()
set this.values = this.values - 1
endmethod
/*
Destroys the element at ind and replaces it with with.
Removes the memory for the underlying object
Must be an object at element ind!
*/
public method replace takes integer ind, $TYPE$ with returns nothing
local $TYPE$ toDestroy
if (not(this.hasValueAt(ind))) then
call BJDebugMsg("Array error: No value at element " + I2S(ind) + " when trying to mutate element, report this bug to the map maker!")
return
endif
set toDestroy = LoadInteger(hashtables, this.tableInd, ind)
call SaveInteger(hashtables, this.tableInd, ind, with)
call toDestroy.destroy()
endmethod
public method top takes nothing returns $TYPE$
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
return -1
endif
return LoadInteger(hashtables, this.tableInd, this.values -1)
endmethod
public method bottom takes nothing returns $TYPE$
if this.values == 0 then
call BJDebugMsg("Array error: table is EMPTY, report this bug to the map maker!")
return -1
endif
return LoadInteger(hashtables, this.tableInd, 0)
endmethod
public method size takes nothing returns integer
return this.values
endmethod
public method hashtableIndex takes nothing returns integer
return this.tableInd
endmethod
public method hasValueAt takes integer ind returns boolean
return HaveSavedInteger(hashtables, this.tableInd, ind)
endmethod
//this method will not deallocate the underlying objects
public method flush takes nothing returns nothing
call FlushChildHashtable(hashtables, this.tableInd)
set this.values = 0
endmethod
//identitcal to flush, but also destroys the underlying objects
public method cleansAll takes nothing returns nothing
loop
exitwhen this.values == 0
call this.destroyTop()
endloop
call this.flush()
endmethod
//flags wantDestroy to the desired value
//if wantDestroy is flagged, cleansAll() is called upon destruction rather than flush()
public method setWantDestroy takes boolean to returns nothing
set this.wantDestroy = to
endmethod
public method isWantDestroy takes nothing returns boolean
return this.wantDestroy
endmethod
public method onDestroy takes nothing returns nothing
if deallocTable(this.tableInd) == -1 then
call BJDebugMsg("Hashtable deallocation failed! Report this issue to the map maker.")
endif
if (this.wantDestroy) then
call this.cleansAll()
else
call this.flush()
endif
endmethod
endstruct
//! endtextmacro
JASS:
library containers initializer init requires TriggerUtil
globals
private constant integer MAX_TABLES = 1500
private integer array freeIndices
private integer tos = 0
public hashtable hashtables = InitHashtable()
endglobals
private function init takes nothing returns nothing
local integer i = 0
loop
set freeIndices[i] = i
set i = i + 1
exitwhen i == MAX_TABLES
endloop
endfunction
public function allocTable takes nothing returns integer
local integer index = freeIndices[tos]
if tos == MAX_TABLES then
set tos = tos - 1
call BJDebugMsg("Max hashtables reached. Allocation failed.")
return -1
endif
set tos = tos + 1
return index
endfunction
public function deallocTable takes integer ind returns integer
if tos == 0 then
call BJDebugMsg("Deallocation failed. There are no tables to deallocate!")
return -1
endif
set tos = tos - 1
set freeIndices[tos] = ind
return 0
endfunction
//! runtextmacro mapValueType("Str", "string", "String", "StringHash", "String", "string")
//! runtextmacro arrayValueType("Boolean", "Boolean", "boolean")
//! runtextmacro arrayValueType("Integer", "Integer", "integer")
//! runtextmacro arrayValueType("Real", "Real", "real")
//! runtextmacro arrayValueType("Str", "String", "string")
//! runtextmacro arrayHandleType("Ability", "ability", "TriggerUtil_dummy")
//! runtextmacro arrayHandleType("Button", "button", "TriggerUtil_dummy")
//! runtextmacro arrayHandleType("DefeatCondition", "defeatcondition", "DestroyDefeatCondition")
//! runtextmacro arrayHandleType("Destructable", "destructable", "RemoveDestructable")
//! runtextmacro arrayHandleType("Dialog", "dialog", "DialogDestroy")
//! runtextmacro arrayHandleType("Effect", "effect", "DestroyEffect")
//! runtextmacro arrayHandleType("FogModifier", "fogmodifier", "DestroyFogModifier")
//! runtextmacro arrayHandleType("FogState", "fogstate", "TriggerUtil_dummy")
//! runtextmacro arrayHandleType("Force", "force", "DestroyForce")
//! runtextmacro arrayHandleType("Group", "group", "DestroyGroup")
//! runtextmacro arrayHandleType("Hashtable", "hashtable", "FlushParentHashtable")
//! runtextmacro arrayHandleType("Image", "image", "DestroyImage")
//! runtextmacro arrayHandleType("Item", "item", "RemoveItem")
//! runtextmacro arrayHandleType("ItemPool", "itempool", "DestroyItemPool")
//! runtextmacro arrayHandleType("Leaderboard", "leaderboard", "DestroyLeaderboard")
//! runtextmacro arrayHandleType("Lightning", "lightning", "DestroyLightning")
//! runtextmacro arrayHandleType("Location", "location", "RemoveLocation")
//! runtextmacro arrayHandleType("Multiboard", "multiboard", "DestroyMultiboard")
//! runtextmacro arrayHandleType("MultiboardItem", "multiboarditem", "MultiboardReleaseItem")
//! runtextmacro arrayHandleType("Player", "player", "TriggerUtil_dummy")
//! runtextmacro arrayHandleType("Quest", "quest", "DestroyQuest")
//! runtextmacro arrayHandleType("QuestItem", "questitem", "TriggerUtil_dummy")
//! runtextmacro arrayHandleType("Rect", "rect", "RemoveRect")
//! runtextmacro arrayHandleType("Sound", "sound", "TriggerUtil_dummy")
//! runtextmacro arrayHandleType("TextTag", "texttag", "DestroyTextTag")
//! runtextmacro arrayHandleType("TimerDialog", "timerdialog", "DestroyTimerDialog")
//! runtextmacro arrayHandleType("Timer", "timer", "DestroyTimer")
//! runtextmacro arrayHandleType("Trackable", "trackable", "TriggerUtil_dummy")
//! runtextmacro arrayHandleType("TriggerAction", "triggeraction", "TriggerUtil_dummy")
//! runtextmacro arrayHandleType("TriggerCondition", "triggercondition", "TriggerUtil_dummy")
//! runtextmacro arrayHandleType("TriggerEvent", "event", "TriggerUtil_dummy")
//! runtextmacro arrayHandleType("Trigger", "trigger", "DestroyTrigger")
//! runtextmacro arrayHandleType("Ubersplat", "ubersplat", "DestroyUbersplat")
//! runtextmacro arrayHandleType("Unit", "unit", "RemoveUnit")
//! runtextmacro arrayHandleType("UnitPool", "unitpool", "DestroyUnitPool")
//! runtextmacro arrayHandleType("Widget", "widget", "TriggerUtil_dummy")
endlibrary
JASS:
function myCallback takes nothing returns nothing
call DisplayTextToPlayer(Player(0), 0, 0, "Hello from a trigger")
endfunction
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
local integer i = 0
local tables_TriggerTable myTable = tables_TriggerTable.create()
local tables_TriggerTableTable inner = tables_TriggerTableTable.create()
local trigger t = CreateTrigger()
call inner.push(myTable)
call myTable.push(t)
call TriggerAddAction(t, function myCallback)
call TriggerExecute(inner.top()[0])
if (inner.top().hasValueAt(0)) then
call DisplayTextToPlayer(Player(0), 0, 0, "Has a value")
else
call DisplayTextToPlayer(Player(0), 0, 0, "Doesn't have a value")
endif
if (inner.top().hasValueAt(1)) then
call DisplayTextToPlayer(Player(0), 0, 0, "Has a value")
else
call DisplayTextToPlayer(Player(0), 0, 0, "Doesn't have a value")
endif
call myTable.setWantDestroy(true)
call inner.setWantDestroy(true)
call inner.destroy()
set t = null
endfunction
//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing
set gg_trg_Untitled_Trigger_001 = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_Untitled_Trigger_001, 0.00 )
call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions )
endfunction
JASS:
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
local containers_StringToStringMap people = containers_StringToStringMap.create()
call people.push("Patrick Leonard", "Kinda nerdy guy with a lot of unexpected twists hidden just under the surface. Likes C#.")
call people.push("Destiny Showman", "Patrick's Girlfriend, a very sweet, loving, caring girl. Not the brightest one in the bunch though (don't tell her I said that I love her very much). HOWEVER, she has excellent memory and is very insightful.")
call DisplayTextToPlayer(Player(0), 0, 0, people["Patrick Leonard"])
call DisplayTextToPlayer(Player(0), 0, 0, people["Destiny Showman"])
call DisplayTextToPlayer(Player(0), 0, 0, people["ME DOZ NOT EXIST"])
endfunction
//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing
set gg_trg_Untitled_Trigger_001 = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_Untitled_Trigger_001, 0.01 )
call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions )
endfunction
Last edited: