System ABC - Struct Attachment System

Romek

Super Moderator
Reaction score
963
I'd love to know if hashing, ifs and arrays are significantly faster than just using hashtables directly. :(
 
Reaction score
91
I've been wondering for a long time how this type of hashing actually works:
JASS:

    local integer i = GetHandleId(key)
    set i = i - (i / HASH) * HASH

Shouldn't i be set to 0 every time and thus overriding the same array index (0)?
 

Jesus4Lyf

Good Idea™
Reaction score
397
>set i = i - (i / HASH) * HASH
Because i / HASH is in brackets, it gets calculated first. Into an integer. Which means it gets rounded down. So what (i / HASH) * HASH returns is HASH multiplied by the number of times it can be subtracted from i without i becoming negative.

So say... HASH is 8000, and i is 12000.

set i = 12000 - (12000 / 8000) * 8000
set i = 12000 - (1.5) * 8000
set i = 12000 - (1) * 8000 // Because it is calculating integers.
set i = 12000 - 8000
set i = 4000

Something like that. :)

>I'd love to know if hashing, ifs and arrays are significantly faster than just using hashtables directly.
I'd love to know if hashtables are fast. XD
 

Romek

Super Moderator
Reaction score
963
That hash is basically ModuloInteger.
If you know what that does, and how it works; you'll understand that.
 

RaiJin

New Member
Reaction score
40
i thought this was updated to 1.24... its using GetHandleId so it must be compatible, oh well lets just wait then
 

Jesus4Lyf

Good Idea™
Reaction score
397
Sorry I can't test this myself, as I don't have WC3 with me right now, but try this, perhaps.
JASS:
//==============================================================================
//  ABC -- STRUCT ATTACHMENT SYSTEM BY COHADAR -- v6.1 (Unofficially Modified)
//==============================================================================


//==============================================================================
//  Quick function index:
//==============================================================================
//
//    ----------------------------------------------------------------------
//      Set Functions - these functions attach struct to a handle
//    ----------------------------------------------------------------------
//    SetTimerStructA(timer, struct)
//    SetTimerStructB(timer, struct)
//    SetTimerStructC(timer, struct)
//
//    SetTriggerStructA(trigger, struct)
//    SetTriggerStructB(trigger, struct)
//    SetTriggerStructC(trigger, struct)
//
//    SetDialogStructA(dialog, struct)
//    SetDialogStructB(dialog, struct)
//    SetDialogStructC(dialog, struct)
//
//    SetRegionStructA(region, struct)
//    SetRegionStructB(region, struct)
//    SetRegionStructC(region, struct)
//
//    ----------------------------------------------------------------------
//      Get Functions - these functions retrieve attached structs
//    ----------------------------------------------------------------------
//    GetTimerStructA(timer) -> struct
//    GetTimerStructB(timer) -> struct
//    GetTimerStructC(timer) -> struct
//
//    GetTriggerStructA(trigger) -> struct
//    GetTriggerStructB(trigger) -> struct
//    GetTriggerStructC(trigger) -> struct
//
//    GetDialogStructA(dialog) -> struct
//    GetDialogStructB(dialog) -> struct
//    GetDialogStructC(dialog) -> struct
//
//    GetRegionStructA(region) -> struct
//    GetRegionStructB(region) -> struct
//    GetRegionStructC(region) -> struct
//
//    ----------------------------------------------------------------------
//      Clear Functions - these functions clear and return attached value
//    ----------------------------------------------------------------------
//    ClearTimerStructA(timer) -> struct
//    ClearTimerStructB(timer) -> struct
//    ClearTimerStructC(timer) -> struct
//
//    ClearTriggerStructA(trigger) -> struct
//    ClearTriggerStructB(trigger) -> struct
//    ClearTriggerStructC(trigger) -> struct
//
//    ClearDialogStructA(dialog) -> struct
//    ClearDialogStructB(dialog) -> struct
//    ClearDialogStructC(dialog) -> struct
//
//    ClearRegionStructA(region) -> struct
//    ClearRegionStructB(region) -> struct
//    ClearRegionStructC(region) -> struct
//
//==============================================================================


//==============================================================================
//  DOCUMENTATION:
//==============================================================================
//
//  PURPOUSE OF ABC:
//       * Type safe handle attaching.
//      
//       * Currently supported handle types are timer, trigger, dialog and region
//
//  PROS: 
//       * ABC is faster than gamecache based systems.
//
//       * You can attach up to 3 structs on the same handle
//         
//       * System reports collision, and clearing of non-existent value.
//
//       * This system will work even if your map leaks
//         and will NOT slow down because of it.
//
//  CONS:
//       * you must manually clear the stored value - REMEMBER THIS RULE!!!
//         Don't forget to use Clear functions
//
//  DETAILS:
//       * You can use Get to check if struct is attached to handle
//         It will return 0 if it is not.
//
//       * ABC will not interfere with other attachment systems
//         You can freely use any other system alongside ABC
//
//       * For unit attaching I recommend using PUI
//
//  SPECIAL THANKS TO: 
//       * NagelBagel - for finding errors in versions 4.3 and 4.4
//       * Here-b-Trollz - for testing ABC and for making cool spells with it.
//       * Toadcop - for being pain in the ass and for pushing me to improve ABC.
//       * emjlr3 - for pointing out the need for non-generic trigger attachments
//       * PandaMine - I found a bug in ABC by examining his HSAS vs ABC test
//       * All those people out there who use and support my systems
//         Thank you guys.
//
//  HOW TO IMPORT:
//       * Just create a trigger named ABC
//       * convert it to text and replace the whole trigger text with this one
//
//==============================================================================


//==============================================================================
//  Macro function cores
//==============================================================================

//------------------------------------------------------------------------------
//! textmacro ABC_Set takes X, NAME, TYPE
    local integer i = GetHandleId(key)
    set i = i - (i / HASH) * HASH

    if $NAME$Key$X$<i> == null then
        set $NAME$Key$X$<i> = key
        set $NAME$Value$X$<i> = value
    else
        debug   set $NAME$Collision$X$<i> = $NAME$Collision$X$<i> + 1
        debug   if $NAME$MaxCollision$X$ &lt; $NAME$Collision$X$<i> then
        debug       set $NAME$MaxCollision$X$ = $NAME$Collision$X$<i>
        debug       call BJDebugMsg(&quot;|cFFFF00FFWarning: Set$NAME$Struct$X$(&quot;+I2S(GetHandleId(key))+&quot;, &quot;+I2S(value)+&quot;) - index: &quot;+I2S(i)+&quot;, collision: &quot;+I2S($NAME$MaxCollision$X$))
        debug   endif
        call SaveInteger($NAME$Hash, &#039;$X$&#039;, GetHandleId(key), value)
        endif
//! endtextmacro

//------------------------------------------------------------------------------
//! textmacro ABC_Get takes X, NAME, TYPE
    local integer i = GetHandleId(key)
    set i = i - (i / HASH) * HASH
        
    if $NAME$Key$X$<i> == key then
        return $NAME$Value$X$<i>
    endif
    return LoadInteger($NAME$Hash, &#039;$X$&#039;, GetHandleId(key))
//! endtextmacro    

//------------------------------------------------------------------------------
//! textmacro ABC_Clear takes X, NAME, TYPE
    local integer ret
    local integer i = GetHandleId(key)
    set i = i - (i / HASH) * HASH
        
    if $NAME$Key$X$<i> == key then
        set ret = $NAME$Value$X$<i>
        set $NAME$Key$X$<i> = null
        set $NAME$Value$X$<i> = 0
    else
        if HaveSavedInteger($NAME$Hash, &#039;$X$&#039;, GetHandleId(key)) then
            debug set $NAME$Collision$X$<i> = $NAME$Collision$X$<i> - 1
            set ret = LoadInteger($NAME$Hash, &#039;$X$&#039;, GetHandleId(key))
            call RemoveSavedInteger($NAME$Hash, &#039;$X$&#039;, GetHandleId(key))
        else
            call BJDebugMsg(&quot;|cFFFF0000ERROR: Clear$NAME$Struct$X$(&quot;+I2S(GetHandleId(key))+&quot;) - clear attempt on bad key&quot;)
            set ret = 0
        endif
    endif
    
    return ret
//! endtextmacro    


//==============================================================================
library ABC initializer Init

globals
    private constant integer HASH = 8191

    private timer   array TimerKeyA
    private timer   array TimerKeyB
    private timer   array TimerKeyC
    private trigger array TriggerKeyA
    private trigger array TriggerKeyB
    private trigger array TriggerKeyC
    private dialog  array DialogKeyA
    private dialog  array DialogKeyB
    private dialog  array DialogKeyC
    private region  array RegionKeyA
    private region  array RegionKeyB
    private region  array RegionKeyC
    
    private integer array TimerValueA
    private integer array TimerValueB
    private integer array TimerValueC
    private integer array TriggerValueA
    private integer array TriggerValueB
    private integer array TriggerValueC
    private integer array DialogValueA
    private integer array DialogValueB
    private integer array DialogValueC
    private integer array RegionValueA
    private integer array RegionValueB
    private integer array RegionValueC

    private integer array TimerCollisionA
    private integer array TimerCollisionB
    private integer array TimerCollisionC
    private integer array TriggerCollisionA
    private integer array TriggerCollisionB
    private integer array TriggerCollisionC
    private integer array DialogCollisionA
    private integer array DialogCollisionB
    private integer array DialogCollisionC
    private integer array RegionCollisionA
    private integer array RegionCollisionB
    private integer array RegionCollisionC    
    
    private integer TimerMaxCollisionA   = 0
    private integer TimerMaxCollisionB   = 0
    private integer TimerMaxCollisionC   = 0
    private integer TriggerMaxCollisionA = 0
    private integer TriggerMaxCollisionB = 0
    private integer TriggerMaxCollisionC = 0
    private integer DialogMaxCollisionA  = 0
    private integer DialogMaxCollisionB  = 0
    private integer DialogMaxCollisionC  = 0
    private integer RegionMaxCollisionA  = 0
    private integer RegionMaxCollisionB  = 0
    private integer RegionMaxCollisionC  = 0 
    
    private hashtable TimerHash
    private hashtable TriggerHash
    private hashtable DialogHash
    private hashtable RegionHash
endglobals

//==============================================================================
//  Collision check functions
//==============================================================================

//------------------------------------------------------------------------------
function GetTimerCollisionA takes nothing returns integer
    return TimerMaxCollisionA
endfunction

//------------------------------------------------------------------------------
function GetTimerCollisionB takes nothing returns integer
    return TimerMaxCollisionB
endfunction

//------------------------------------------------------------------------------
function GetTimerCollisionC takes nothing returns integer
    return TimerMaxCollisionC
endfunction

//------------------------------------------------------------------------------
function GetTriggerCollisionA takes nothing returns integer
    return TriggerMaxCollisionA
endfunction

//------------------------------------------------------------------------------
function GetTriggerCollisionB takes nothing returns integer
    return TriggerMaxCollisionB
endfunction

//------------------------------------------------------------------------------
function GetTriggerCollisionC takes nothing returns integer
    return TriggerMaxCollisionC
endfunction

//------------------------------------------------------------------------------
function GetDialogCollisionA takes nothing returns integer
    return DialogMaxCollisionA
endfunction

//------------------------------------------------------------------------------
function GetDialogCollisionB takes nothing returns integer
    return DialogMaxCollisionB
endfunction

//------------------------------------------------------------------------------
function GetDialogCollisionC takes nothing returns integer
    return DialogMaxCollisionC
endfunction

//------------------------------------------------------------------------------
function GetRegionCollisionA takes nothing returns integer
    return RegionMaxCollisionA
endfunction

//------------------------------------------------------------------------------
function GetRegionCollisionB takes nothing returns integer
    return RegionMaxCollisionB
endfunction

//------------------------------------------------------------------------------
function GetRegionCollisionC takes nothing returns integer
    return RegionMaxCollisionC
endfunction


//==============================================================================
//  Set functions
//==============================================================================

//------------------------------------------------------------------------------
function SetTimerStructA takes timer key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;A&quot;, &quot;Timer&quot;, &quot;timer&quot;)
endfunction

//------------------------------------------------------------------------------
function SetTimerStructB takes timer key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;B&quot;, &quot;Timer&quot;, &quot;timer&quot;)
endfunction

//------------------------------------------------------------------------------
function SetTimerStructC takes timer key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;C&quot;, &quot;Timer&quot;, &quot;timer&quot;)
endfunction

//------------------------------------------------------------------------------
function SetTriggerStructA takes trigger key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;A&quot;, &quot;Trigger&quot;, &quot;trigger&quot;)
endfunction

//------------------------------------------------------------------------------
function SetTriggerStructB takes trigger key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;B&quot;, &quot;Trigger&quot;, &quot;trigger&quot;)
endfunction

//------------------------------------------------------------------------------
function SetTriggerStructC takes trigger key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;C&quot;, &quot;Trigger&quot;, &quot;trigger&quot;)
endfunction

//------------------------------------------------------------------------------
function SetDialogStructA takes dialog key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;A&quot;, &quot;Dialog&quot;, &quot;dialog&quot;)
endfunction

//------------------------------------------------------------------------------
function SetDialogStructB takes dialog key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;B&quot;, &quot;Dialog&quot;, &quot;dialog&quot;)
endfunction

//------------------------------------------------------------------------------
function SetDialogStructC takes dialog key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;C&quot;, &quot;Dialog&quot;, &quot;dialog&quot;)
endfunction

//------------------------------------------------------------------------------
function SetRegionStructA takes region key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;A&quot;, &quot;Region&quot;, &quot;region&quot;)
endfunction

//------------------------------------------------------------------------------
function SetRegionStructB takes region key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;B&quot;, &quot;Region&quot;, &quot;region&quot;)
endfunction

//------------------------------------------------------------------------------
function SetRegionStructC takes region key, integer value returns nothing
//! runtextmacro ABC_Set(&quot;C&quot;, &quot;Region&quot;, &quot;region&quot;)
endfunction


//==============================================================================
//  Get functions
//==============================================================================

//------------------------------------------------------------------------------
function GetTimerStructA takes timer key returns integer
//! runtextmacro ABC_Get(&quot;A&quot;, &quot;Timer&quot;, &quot;timer&quot;)
endfunction

//------------------------------------------------------------------------------
function GetTimerStructB takes timer key returns integer
//! runtextmacro ABC_Get(&quot;B&quot;, &quot;Timer&quot;, &quot;timer&quot;)
endfunction

//------------------------------------------------------------------------------
function GetTimerStructC takes timer key returns integer
//! runtextmacro ABC_Get(&quot;C&quot;, &quot;Timer&quot;, &quot;timer&quot;)
endfunction

//------------------------------------------------------------------------------
function GetTriggerStructA takes trigger key returns integer
//! runtextmacro ABC_Get(&quot;A&quot;, &quot;Trigger&quot;, &quot;trigger&quot;)
endfunction

//------------------------------------------------------------------------------
function GetTriggerStructB takes trigger key returns integer
//! runtextmacro ABC_Get(&quot;B&quot;, &quot;Trigger&quot;, &quot;trigger&quot;)
endfunction

//------------------------------------------------------------------------------
function GetTriggerStructC takes trigger key returns integer
//! runtextmacro ABC_Get(&quot;C&quot;, &quot;Trigger&quot;, &quot;trigger&quot;)
endfunction

//------------------------------------------------------------------------------
function GetDialogStructA takes dialog key returns integer
//! runtextmacro ABC_Get(&quot;A&quot;, &quot;Dialog&quot;, &quot;dialog&quot;)
endfunction

//------------------------------------------------------------------------------
function GetDialogStructB takes dialog key returns integer
//! runtextmacro ABC_Get(&quot;B&quot;, &quot;Dialog&quot;, &quot;dialog&quot;)
endfunction

//------------------------------------------------------------------------------
function GetDialogStructC takes dialog key returns integer
//! runtextmacro ABC_Get(&quot;C&quot;, &quot;Dialog&quot;, &quot;dialog&quot;)
endfunction

//------------------------------------------------------------------------------
function GetRegionStructA takes region key returns integer
//! runtextmacro ABC_Get(&quot;A&quot;, &quot;Region&quot;, &quot;region&quot;)
endfunction

//------------------------------------------------------------------------------
function GetRegionStructB takes region key returns integer
//! runtextmacro ABC_Get(&quot;B&quot;, &quot;Region&quot;, &quot;region&quot;)
endfunction

//------------------------------------------------------------------------------
function GetRegionStructC takes region key returns integer
//! runtextmacro ABC_Get(&quot;C&quot;, &quot;Region&quot;, &quot;region&quot;)
endfunction


//==============================================================================
//  Clear functions
//==============================================================================

//------------------------------------------------------------------------------
function ClearTimerStructA takes timer key returns integer
//! runtextmacro ABC_Clear(&quot;A&quot;, &quot;Timer&quot;, &quot;timer&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearTimerStructB takes timer key returns integer
//! runtextmacro ABC_Clear(&quot;B&quot;, &quot;Timer&quot;, &quot;timer&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearTimerStructC takes timer key returns integer
//! runtextmacro ABC_Clear(&quot;C&quot;, &quot;Timer&quot;, &quot;timer&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearTriggerStructA takes trigger key returns integer
//! runtextmacro ABC_Clear(&quot;A&quot;, &quot;Trigger&quot;, &quot;trigger&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearTriggerStructB takes trigger key returns integer
//! runtextmacro ABC_Clear(&quot;B&quot;, &quot;Trigger&quot;, &quot;trigger&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearTriggerStructC takes trigger key returns integer
//! runtextmacro ABC_Clear(&quot;C&quot;, &quot;Trigger&quot;, &quot;trigger&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearDialogStructA takes dialog key returns integer
//! runtextmacro ABC_Clear(&quot;A&quot;, &quot;Dialog&quot;, &quot;dialog&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearDialogStructB takes dialog key returns integer
//! runtextmacro ABC_Clear(&quot;B&quot;, &quot;Dialog&quot;, &quot;dialog&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearDialogStructC takes dialog key returns integer
//! runtextmacro ABC_Clear(&quot;C&quot;, &quot;Dialog&quot;, &quot;dialog&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearRegionStructA takes region key returns integer
//! runtextmacro ABC_Clear(&quot;A&quot;, &quot;Region&quot;, &quot;region&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearRegionStructB takes region key returns integer
//! runtextmacro ABC_Clear(&quot;B&quot;, &quot;Region&quot;, &quot;region&quot;)
endfunction

//------------------------------------------------------------------------------
function ClearRegionStructC takes region key returns integer
//! runtextmacro ABC_Clear(&quot;C&quot;, &quot;Region&quot;, &quot;region&quot;)
endfunction


//==============================================================================
//  Initialization
//==============================================================================
private function Init takes nothing returns nothing
    set TimerKeyA[HASH-1] = null
    set TimerKeyB[HASH-1] = null
    set TimerKeyC[HASH-1] = null
    set TriggerKeyA[HASH-1] = null
    set TriggerKeyB[HASH-1] = null
    set TriggerKeyC[HASH-1] = null
    set DialogKeyA[HASH-1] = null
    set DialogKeyB[HASH-1] = null
    set DialogKeyC[HASH-1] = null
    set RegionKeyA[HASH-1] = null
    set RegionKeyB[HASH-1] = null
    set RegionKeyC[HASH-1] = null
    
    set TimerValueA[HASH-1] = 0
    set TimerValueB[HASH-1] = 0
    set TimerValueC[HASH-1] = 0
    set TriggerValueA[HASH-1] = 0
    set TriggerValueB[HASH-1] = 0
    set TriggerValueC[HASH-1] = 0
    set DialogValueA[HASH-1] = 0
    set DialogValueB[HASH-1] = 0
    set DialogValueC[HASH-1] = 0
    set RegionValueA[HASH-1] = 0
    set RegionValueB[HASH-1] = 0
    set RegionValueC[HASH-1] = 0    
    
    set TimerCollisionA[HASH-1] = 0
    set TimerCollisionB[HASH-1] = 0
    set TimerCollisionC[HASH-1] = 0
    set TriggerCollisionA[HASH-1] = 0
    set TriggerCollisionB[HASH-1] = 0
    set TriggerCollisionC[HASH-1] = 0
    set DialogCollisionA[HASH-1] = 0
    set DialogCollisionB[HASH-1] = 0
    set DialogCollisionC[HASH-1] = 0
    set RegionCollisionA[HASH-1] = 0
    set RegionCollisionB[HASH-1] = 0
    set RegionCollisionC[HASH-1] = 0    
    
    set TimerHash   = InitHashtable()
    set TriggerHash = InitHashtable()
    set DialogHash  = InitHashtable()
    set RegionHash  = InitHashtable()
endfunction

endlibrary
//==============================================================================
//  END OF ABC STRUCT ATTACHMENT SYSTEM
//==============================================================================

</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>

What's not working about it? Does the map not load at all? Are you sure it's ABC's fault? Does it fatal after loading? On loading? Have you tested ABC in a map by itself?
 

trb92

Throwing science at the wall to see what sticks
Reaction score
142
It's probably because of this:
JASS:
function SetTimerStructA takes timer key, integer value returns nothing

And all the other SetStruct functions. key is a type now, so you shouldn't be able to use it as a variable name like that.
 

Faust

You can change this now in User CP.
Reaction score
123
Cohadar, what would your answer be to "Why does it have A, B and C, they are all the same, no?".
 
Reaction score
91
> "Why does it have A, B and C, they are all the same, no?"
// * You can attach up to 3 structs on the same handle
Which means if you're only attaching 1 struct you'd be using only Set/GetXXXStructA, if you're attaching 2 structs then you'd be using A and B for the separate instances and the same applies for C.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top