Cohadar
master of fugue
- Reaction score
- 209
Version 2.0
Old Version:
And here is a test map with a slide spell as a proof of concept.
Code:
//==============================================================================
// STRUCT ATTACHMENT SYSTEM BY COHADAR
//==============================================================================
//
// PURPOUSE:
// * Attaching structs to a handle (unit, group, item, timer ...)
//
// PROS:
// * you can attach any struct to any handle
// * get and set functions are extremelly fast (using hash algorithm)
// * get(handle, true) function clears setted value,
// so you don't have to do it yourself
// * system reports overflow and unknown handle requests
// also has debug messages for collision efficiency testing
// * this system will work even if your map leaks
//
// CONS:
// * you can have only 8192 attached structs at any time
// * you canNOT attach 2 structs on same handle (second erases the first one)
//
// DETAILS:
// * we are using the fact that structs never have zero index
// to mark unused entries in hash table
// * probability of collision is approximately 1/8192 = 0.012% = almost never
// * collision is not an error, it will only slow functions down
// * when struct is deatached from handle it is not destroyed
// you still have to do that manually if necessary
//
// HOW TO IMPORT:
// * Just create a trigger named SAS
// * convert it to text and replace the whole trigger text with this one
//
//==============================================================================
library StructAttachmentSystem
//------------------------------------------------------------------------------
// global arrays represent our hash table
//------------------------------------------------------------------------------
globals
constant integer ARRAY_SIZE = 8192 // full hash size
handle array Handles
integer array Structs
integer Counter = 0
integer oldCollision = 0
endglobals
//------------------------------------------------------------------------------
// converts handle to integer
//------------------------------------------------------------------------------
function C_H2I takes handle h returns integer i
return h
return 0
endfunction
//------------------------------------------------------------------------------
// Prints out collision size (debug mode only)
//------------------------------------------------------------------------------
function ReportCollision takes integer newCollision returns nothing
if (oldCollision != newCollision) then
call BJDebugMsg("Collision size: "+I2S(newCollision)+" Hash size: "+I2S(Counter))
set oldCollision = newCollision
endif
endfunction
//------------------------------------------------------------------------------
// attaches integer(struct index) to a handle by using hash table
//------------------------------------------------------------------------------
function SetStruct takes handle h, integer s returns nothing
local integer i
local integer startingHash
set i = ModuloInteger(C_H2I(h), ARRAY_SIZE)
set startingHash = i
if (Structs[i] == 0) then
set Structs[i] = s
set Handles[i] = h
set Counter = Counter + 1
return
else
// hash collision
// it will almost never happen, and even if it does
// it will never get bigger than 10 because wc3 is using
// incremental memory allocation
// find next available hash value
loop
set i = i + 1
exitwhen i >= ARRAY_SIZE
if (Structs[i] == 0) then
set Structs[i] = s
set Handles[i] = h
set Counter = Counter + 1
debug call ReportCollision(i-startingHash)
return
endif
endloop
// start from the beginning
set i = 0
loop
exitwhen i >= startingHash
if (Structs[i] == 0) then
set Structs[i] = s
set Handles[i] = h
set Counter = Counter + 1
debug call ReportCollision(ARRAY_SIZE-startingHash+i)
return
endif
set i = i + 1
endloop
call BJDebugMsg("|cFFFF0000ERROR: Hash overflow")
endif
endfunction
//------------------------------------------------------------------------------
// gets integer(struct index) from a handle
// optionally clears a hash entry (removes handle attachment)
//------------------------------------------------------------------------------
function GetStruct takes handle h, boolean clear returns integer
local integer i
local integer startingHash
local integer ret // return value
set i = ModuloInteger(C_H2I(h), ARRAY_SIZE)
set startingHash = i
if (Structs[i] != 0 and Handles[i] == h) then
set ret = Structs[i]
if (clear == true) then
set Structs[i] = 0
set Handles[i] = null
set Counter = Counter - 1
endif
return ret
else
// hash collision
// it will almost never happen, and even if it does
// it will never get bigger than 10 because wc3 is using
// incremental memory allocation
// find next available hash value
loop
set i = i + 1
exitwhen i >= ARRAY_SIZE
if (Structs[i] != 0 and Handles[i] == h) then
set ret = Structs[i]
if (clear == true) then
set Structs[i] = 0
set Handles[i] = null
set Counter = Counter - 1
endif
debug call ReportCollision(i-startingHash)
return ret
endif
endloop
// start from the beginning
set i = 0
loop
exitwhen i >= startingHash
if (Structs[i] != 0 and Handles[i] == h) then
set ret = Structs[i]
if (clear == true) then
set Structs[i] = 0
set Handles[i] = null
set Counter = Counter - 1
endif
debug call ReportCollision(ARRAY_SIZE-startingHash+i)
return ret
endif
set i = i + 1
endloop
call BJDebugMsg("|cFFFF0000ERROR: Unknown handle: " + I2S(C_H2I(h)))
return 0
endif
endfunction
endlibrary
//==============================================================================
// END OF STRUCT ATTACHMENT SYSTEM
//==============================================================================
function Trig_SAS_Actions takes nothing returns nothing
endfunction
//===========================================================================
function InitTrig_SAS takes nothing returns nothing
set gg_trg_SAS = CreateTrigger( )
call TriggerAddAction( gg_trg_SAS, function Trig_SAS_Actions )
endfunction
Old Version:
Code:
//==============================================================================
// STRUCT ATTACHMENT SYSTEM BY COHADAR
//==============================================================================
//
// PURPOUSE:
// * Attaching structs to a handle (unit, group, item, timer ...)
//
// PROS:
// * you can attach any struct to any handle
// * get and set functions are extremelly fast (using hash algorithm)
// * get(handle, true) function clears setted value,
// so you don't have to do it yourself
// * system reports overflow and unknown handle requests
// also has debug messages for collision efficiency testing
// * this system will work even if your map leaks
//
// CONS:
// * you can have only 8192 attached structs at any time
// * you canNOT attach 2 structs on same handle (second erases the first one)
//
// DETAILS:
// * we are using the fact that structs never have zero index
// to mark unused entries in hash table
// * probability of collision is approximately 1/8192 = 0.012% = almost never
// * collision is not an error, it will only slow functions down
// * when struct is deatached from handle it is not destroyed
// you still have to do that manually if necessary
//
//==============================================================================
library StructAttachmentSystem
//------------------------------------------------------------------------------
// global arrays represent our hash table
//------------------------------------------------------------------------------
globals
constant integer ARRAY_SIZE = 8192
handle array Handles
integer array Structs
integer Counter = 0
endglobals
//------------------------------------------------------------------------------
// converts handle to integer
//------------------------------------------------------------------------------
function C_H2I takes handle h returns integer i
return h
return 0
endfunction
//------------------------------------------------------------------------------
// attaches integer(struct index) to a handle by using hash table
//------------------------------------------------------------------------------
function SetStruct takes handle h, integer s returns nothing
local integer i
local integer startingHash
set i = ModuloInteger(C_H2I(h), ARRAY_SIZE) // getting the hash value
set startingHash = i
if (Structs[i] == 0) then
set Structs[i] = s
set Handles[i] = h
set Counter = Counter + 1
return
else
// hash collision
// it will almost never happen, and even if it does
// it will never get bigger than 10 because wc3 is using
// incremental memory allocation
// find next available hash value
loop
set i = i + 1
exitwhen i >= ARRAY_SIZE
if (Structs[i] == 0) then
set Structs[i] = s
set Handles[i] = h
set Counter = Counter + 1
debug call BJDebugMsg("Collision size: "+I2S(startingHash-i))
debug call BJDebugMsg("Hash table size: "+I2S(Counter))
return
endif
endloop
// start from the beginning
set i = 0
loop
exitwhen i >= startingHash
if (Structs[i] == 0) then
set Structs[i] = s
set Handles[i] = h
set Counter = Counter + 1
debug call BJDebugMsg("Collision size: "+I2S(ARRAY_SIZE-startingHash+i))
debug call BJDebugMsg("Hash table size: "+I2S(Counter))
return
endif
set i = i + 1
endloop
call BJDebugMsg("ERROR: Hash overflow")
endif
endfunction
//------------------------------------------------------------------------------
// gets integer(struct index) from a handle
// optionally clears a hash entry (removes handle attachment)
//------------------------------------------------------------------------------
function GetStruct takes handle h, boolean clear returns integer
local integer i
local integer startingHash
local integer ret // return value
set i = ModuloInteger(C_H2I(h), ARRAY_SIZE) // getting the hash value
set startingHash = i
if (Structs[i] != 0 and Handles[i] == h) then
set ret = Structs[i]
if (clear == true) then
set Structs[i] = 0
set Handles[i] = null
endif
return ret
else
// hash collision
// it will almost never happen, and even if it does
// it will never get bigger than 10 because wc3 is using
// incremental memory allocation
// find next available hash value
loop
set i = i + 1
exitwhen i >= ARRAY_SIZE
if (Structs[i] != 0 and Handles[i] == h) then
set ret = Structs[i]
if (clear == true) then
set Structs[i] = 0
set Handles[i] = null
endif
debug call BJDebugMsg("Collision size: "+I2S(startingHash-i))
debug call BJDebugMsg("Hash table size: "+I2S(Counter))
return ret
endif
endloop
// start from the beginning
set i = 0
loop
exitwhen i >= startingHash
if (Structs[i] != 0 and Handles[i] == h) then
set ret = Structs[i]
if (clear == true) then
set Structs[i] = 0
set Handles[i] = null
endif
debug call BJDebugMsg("Collision size: "+I2S(ARRAY_SIZE-startingHash+i))
debug call BJDebugMsg("Hash table size: "+I2S(Counter))
return ret
endif
set i = i + 1
endloop
call BJDebugMsg("ERROR: Unknown handle: " + I2S(C_H2I(h)))
return 0
endif
endfunction
endlibrary
//==============================================================================
// END OF STRUCT ATTACHMENT SYSTEM
//==============================================================================
function Trig_SAS_Actions takes nothing returns nothing
endfunction
//===========================================================================
function InitTrig_SAS takes nothing returns nothing
set gg_trg_SAS = CreateTrigger( )
call TriggerAddAction( gg_trg_SAS, function Trig_SAS_Actions )
endfunction
And here is a test map with a slide spell as a proof of concept.