Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

HandleIndexing + Recycling.

Discussion in 'Graveyard' started by MapperMalte, Mar 2, 2009.

  1. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    What is this?
    This is a System that created unique integers between 1 and 8190 for
    handles. These values can be used as Index for globals.
    Thats, why this is called 'HandleIndexing'.

    This has the same functionality as PUI, but there are some important differences:
    [*] - HandleIndexing works for each Handle type.
    [*] - HandleIndexing does not use UnitUserData. That makes the whole thing slower, but it is not that slow that it causes laggs. Actually, this system is simple.
    [*] - This is slower than TimerUtils, PUI, DUI, UIU, HSAS ==> whatever.
    But the good things about this is, that you do not have to run textmacros.
    HSAS for example created for each Usage ID/8190 global variables. I think, that is ... Not good. You HAVE to create a tetxmacro for each HSAS usage (static!), because otherwise you overwrite the stored value.


    This is supposed to be combinated with the Recycling textmacro.
    If they are used both, they will cover all your needs for handles.



    And here is the code:
    Recycling
    Code (vJASS):
    //********************************************************************
    // textmacro Recycling takes NAME, TYPE, IDENTIFIER, AMOUNT, ERASELIKE
    // NAME = Enter the name you want to Recycle with. Example: Enter Bottle to create NewBottle() and ReleaseBottle().
    // TYPE = Enter the handle type you want to recycle. timer will create timers to recycle.
    // IDENTIFIER = How is that handle created? Preloaded? If TYPE is timer, this has to be NewTimer().
    // AMOUNT    = How big shall the stack be? The bigger the safer. But this preloads AMOUNT types of the Handle
    //             You want at the map Init, so it lacks all the time some memory.
    // ERASELIKE = How is the handle simulated to be dead? For Timers Write PauseTimer.
    // Dont add the parameters here. They are added automatically. If you don't want simulate death, or it is impossible,
    // set this to Foo.

    // ======= Examples =======
    // Are found below

    // ======= Functions =======
    // New$NAME$()                   : Recycles an old timer, to keep the HandleID size small.
    // Release$NAME$($TYPE$)         : Timers created with NewTimer() must be deleten like this.

    library Plugin
        function Foo takes handle h returns nothing
            set h = null
        endfunction
       
        function P_NewUnitA takes nothing returns unit
            local unit u = CreateUnit(Player(15),'e003',0.,0.,0.)
            call ShowUnit(u, false)
            return u
        endfunction
       
        function P_ReleaseUnit takes unit u returns nothing
            call SetUnitAnimation(u,"death")
            call ShowUnit(u, false)
            //call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl",GetUnitX(u),GetUnitY(u)))
        endfunction
    endlibrary

    //! textmacro Recycling takes NAME, TYPE, IDENTIFIER, ERASELIKE

    library $NAME$Recycling initializer $NAME$Preload requires Plugin

        globals
            integer $NAME$Wanted = 5
            $TYPE$ array $NAME$Handle
        endglobals
       
    function New$NAME$ takes nothing returns $TYPE$
       
         if ( $NAME$Wanted<1 ) then
    [I]        set $NAME$Wanted = $NAME$Wanted + 1
            set $NAME$Handle[$NAME$Wanted] = $IDENTIFIER$[/I] ==> [U]CUT THIS OUT![/U]
            return $IDENTIFIER$
        endif
       
            set $NAME$Wanted = $NAME$Wanted - 1
            return $NAME$Handle[$NAME$Wanted]
    endfunction

    function Release$NAME$ takes $TYPE$ which returns nothing
        set $NAME$Handle[$NAME$Wanted] = which
        set $NAME$Wanted = $NAME$Wanted + 1
        call $ERASELIKE$(which)
    endfunction

    private function $NAME$Preload takes nothing returns nothing
        local integer i = 0
       
        loop
            set i = i + 1
            exitwhen i > $NAME$Wanted
            set $NAME$Handle[i] = $IDENTIFIER$
        endloop
       
    endfunction

    endlibrary

    //! endtextmacro
    //! runtextmacro Recycling( "Group", "group", "CreateGroup()" , "GroupClear")
    // runtextmacro Recycling( "Rect", "rect", "Rect(0.,0.,0.,0.)" , "Foo")
    // runtextmacro Recycling( "Location", "location", "Location(0.,0.)", "Foo")
    // runtextmacro Recycling( "Force", "force", "CreateForce()", "ForceClear")
    // runtextmacro Recycling( "Timer", "timer", "CreateTimer()", "PauseTimer")
    // runtextmacro Recycling( "Dummy", "unit", "P_NewUnitA()", "P_ReleaseUnit)


    You might wonder, what Plugin is used for. The Identifier 'Eraselike' has just one parameter: The handle.
    So if you want for example that the system nulls Locations automatically, you can write this function into 'Plugin' and give the function as parameter.

    Code (vJASS):

    function ClearLocation takes location l returns nothing
            call SetLocationX(l,0.)
            call SetLocationY(l,0.)
    endfunction
     


    Warning: This requires careful handling, because it has not really protections or Debug messages.

    Or as peq code:
    peq - jass-Code #1488 //********************************************************************

    And the two flavours of HandleIndexing.

    <HandleIndexing (Normal)>
    Code (vJASS):
    // ***************************************
    //! S T A R T   O F   H A N D L E   I N D E X I N G
    // ***************************************
    //*********************************************************************
    //* HandleIndexing
    //* ----------
    //*
    //*  To implement it , create a custom text trigger called HandleIndexing
    //* and paste the contents of this script there.
    //*
    //*  To copy from a map to another, copy the trigger holding this
    //* library to your map.
    //*
    //* (requires vJass)   More scripts: htt://www.wc3campaigns.net
    //*
    //* For your needs:
    //*  * Get unique integers between 1 and 8190 for handles.
    //*
    //* set index = Index(handle)    : Gets a unique number that fits into arrays for a handle.
    //* FlushIndex(handle)           : Tells the recycler that this Index can be recycles. Call this, when youre don with the Index.
    //* FlushIndexSafe(handle)       : Flushs an Index using the system itself;
    //* PassIndex(handle,handle)     : Passes ALL the data attached with this system from a handle to another handle.

    //* Features    
    //*             - Doesn't use UnitUserData
    //*             - You Don't have to run textmacros
    //*             - Attaching 15 Data to a unit is almost as fast as attaching 1 Date to a unit.
    //*             - This is safe! If you Release an Index from a unit, that isn't create, the index will instantly be moved to the RecycleBin
    //*             - This is fast! HSAS for example or PUI is faster, but; HSAS needs to run a textmacro for each usage. And it uses extended arrays. That are about 30 globals per macro. PUI uses UnitUserData and I don't like PUIs way to recycle Indexes.
    //*             - If you combinate this with Recycling textmacros, it is perfect to recycle indexes and add Data to them.
    //*
    //********************************************************************
    //! I M P O R T A N T
    //* If it is possible, that your handle is used in more than one system (like units), Flush the Handle
    //* Only, when the Handle is destroyed!
    //================================================================

    library HandleIndexing
    globals
        private constant integer MAX_HANDLE_ID = 100000
        private constant integer tosub = 0x100000
        private integer array StoredIDs[MAX_HANDLE_ID]
        private integer IDs = 0
        private integer gaps = 0
        private integer array Gaps
    endglobals

    private function h2i takes handle h returns integer
        return h
        return 0
    endfunction

    function ReleaseIndex takes integer index returns nothing
        //! Tell the recycler which gap can be recycled. This will not remove the fitting Index from a unit. ==> lacks memory
        set gaps = gaps + 1
        set Gaps[gaps] = index
    endfunction

    function FlushIndex takes handle h returns integer
        local integer num = h2i(h)-tosub
        local integer re = 0
       
            if ( StoredIDs[num] != 0 ) then
                call ReleaseIndex(StoredIDs[num])
                set re = StoredIDs[num]
                set StoredIDs[num] = 0
            endif
        return re
    endfunction

    function CreateIndex takes integer num returns integer
        //! Recycle Indexes
        if ( gaps > 0 ) then
            set StoredIDs[num] = Gaps[gaps]
            set gaps = gaps - 1
            return StoredIDs[num]
        else
        //! Create new Index
            set IDs = IDs + 1
            set StoredIDs[num] = IDs
            return IDs
        endif
    endfunction

    function Index takes handle h returns integer
        local integer hashnum = h2i(h)-tosub
        if ( StoredIDs[hashnum] == 0 ) then
            return CreateIndex(hashnum)
        else
            return StoredIDs[hashnum]
        endif
    endfunction

    function PassIndex takes handle a, handle b returns nothing
        local integer index = Index(a)
        local integer num = h2i(b)-tosub
        set StoredIDs[num] = index
        call FlushIndex(a)
    endfunction

    endlibrary



    And the Steel Flavour:
    I created this, to add more comfort to HandleIndexing.
    Why is this more comfort?
    Ok. Let's imagine following situation:

    I have 2 systems, both use HandleIndexing. I want to create an Index for a unit in system 2,
    but it was previously created in system 1. (Were talking about the same handle).
    So if you release the Index from system 2 now, the Index from system 1 is recycled, too.
    ===> This is only possible, if the handle is used in more than one system, if it's reachable from each trigger. So if you use for example a Recycling System, this is not problem.
    But it's always a problem, if you have for example units.
    If you use HandleIndexing correctly, you will not experience bugs.
    But remember: If you have units as Handle, there are 2 possibilites to prevent that bug:

    A: Use HandleIndexing Steel
    B: Flush the Index of a unit, when it decays.

    I prefer solution B.

    Because then you have other comfort functions from A.
    However, heres the steel code:
    <HandleIndexing (Steel Flavour)>
    Code (vJASS):
    //| --------------------------------------------- |
    //|                 | ########################### |
    //| HandleIndexing  | #### [ Steel Flavour ] #### |
    //|                 | ########################### |
    //| --------------------------------------------- |
    //
    //            Actually, normal HandleIndexing is the better choice.
    //            But this is suited for noobs and safer.
    //            Differences:
    //  ________________
    // | Differences    |
    // |________________|

    // - You dont have to be careful when you Flush an Index with this Flavour.
    // - Instead of calling Index(handle) to create AND get an Index, you have to
    //   call GetIndex(handle) to return the Index of the unit and
    //   call NewIndex(handle) to create an Index for the unit.
    // - This is slower than the Normal Handle Indexing.
    // - If you use HandleIndexing Steel Flavour, it's veeeeery important that you call ReleaseIndex()!!!!
    // - If you created an Index, you have to release one.

    //  ________________________
    // | How does this work?    |
    // |________________________|

    // - If you call NewIndex(handle), an integer for the Index is increased by 1.
    //   If you call ReleaseIndex(handle) then, the integer is decreased by 1.
    //   If the Integer is 0, the Index is released.


    library SystemAffector
        globals
            integer array Affeted
        endglobals
       
        function Affect takes integer index returns nothing
            set Affeted[index] = Affeted[index] + 1
        endfunction
       
        function DeAffect takes integer index returns boolean
            set Affeted[index] = Affeted[index] - 1
           
            if (Affeted[index] <= 0 ) then
                return true
            endif
            return false
           
        endfunction

    endlibrary


    library HandleIndexingSteel requires SystemAffector
    globals
        private constant integer MAX_HANDLE_ID = 150000
        private constant integer tosub = 0x100000
        private integer array StoredIDs[MAX_HANDLE_ID]
        private integer IDs = 0
        private integer gaps = 0
        private integer array Gaps
    endglobals

    private function h2i takes handle h returns integer
        return h
        return 0
    endfunction

    function ReleaseIndex takes integer index returns nothing
        set gaps = gaps + 1
        set Gaps[gaps] = index
    endfunction

    function CreateIndex takes integer num returns integer
        //! Recycle Indexes
        if ( gaps > 0 ) then
            set StoredIDs[num] = Gaps[gaps]
            set gaps = gaps - 1
            call Affect(StoredIDs[num])
            return StoredIDs[num]
        else
        //! Create new Index
            set IDs = IDs + 1
            set StoredIDs[num] = IDs
               
                    if IDs > 8190 then
                    debug call BJDebugMsg("Handle Indexing; Created too many Indexes! Don't forget to call ReleaseIndex(handle). Trying to fix Issue. May cause Errors or bugs!")
                    return GetRandomInt(1,8190)
                    endif
            call Affect(IDs)
            return IDs
        endif
    endfunction

    function GetIndex takes handle h returns integer
        return StoredIDs[h2i(h)-tosub]
    endfunction

    function NewIndex takes handle h returns integer
        local integer hashnum = h2i(h)-tosub
        if ( StoredIDs[hashnum] == 0 ) then
            return CreateIndex(hashnum)
        else
            call Affect(StoredIDs[hashnum])
            return StoredIDs[hashnum]
        endif
    endfunction

    function FlushIndex takes handle h returns integer
        local integer num = h2i(h)-tosub
        local integer re = 0
       
        if ( DeAffect(StoredIDs[num]) ) then

                call ReleaseIndex(StoredIDs[num])
                set re = StoredIDs[num]
                set StoredIDs[num] = 0
               
        endif
       
        return re
    endfunction

    endlibrary








    Ok. However.
    I said, that HandleIndexing is slower. Well. I did some tests with 500000 executions:
    TEST with StopWatchMark
    === TESTED WITH WAR3ERR DISABLED===


    With 'Safety':
    HandleIndexing: 90% [Called 500k times Index and FlushIndex]
    PUI: 100% [Called 500k times PeriodicRecycler and GetUnitIndex]

    Without 'Safety':
    HandleIndexing: 100% [Called 500k times Index and FlushIndex]
    PUI: 94% [Called 500k times PeriodicRecycler and GetUnitIndex]
    ==> This is, what the systems actually do. A bit code was removed (when Indexes got higher than 8190).
    So actually, this can be faster than PUI.
    PUI is faster, when you call FlushIndex() more than three times a second. However, if you use this for units,
    This can be faster, too. If you Flush the Index when a unit decays:

    EDIT: New results. Updated. HandleIndexing is as fast as PUI. I think they're both almost identically fast.

    http://peeeq.de/gui.php?id=773

    Thats dynamic. Thats faster than PUI. Ok.
    This system is faster than PUI in most usages, but you can't do anything wrong with PUI,
    because it recycles automatically. You have to be more careful with HandleIndexing.

    ===> I was suprised, that the debug messages slower my system by ~35%!
    However, if you use the map finally, you should remove the debug messages.

    Note, that PeriodicRecycler isn't called as often as GetUnitIndex(), but if you play for very long, the Test might fit. Maybe PUI uses even more performance.

    I didn't test UnitIndexingUtils, because I think, that it is the same as PUI, but PUI is safer, because it recycles Indexes automatically (Do you remember the possible bug I explained?)




    And the testcode:

    Code (vJASS):

    library Bench requires PUI, HandleIndexing
    globals
        unit Temp = null
    endglobals
    function IND takes nothing returns nothing
        local integer i = 0
        call RemoveUnit(Temp)
        set Temp = CreateUnit(Player(0),'hpea',0.,0.,0.)
            loop
                set i = i + 1
                exitwhen i > 200
                //CODE FOR THE SYSTEM. IF A SYSTEM IS TESTED ==> RESTART MAP.
            endloop
    endfunction

    function Benchmark takes nothing returns nothing
    local integer sw = StopWatchCreate()
    local real settime1 = StopWatchMark(sw)
    local real settime2 = StopWatchMark(sw)
    local real t1
    local real t0 = StopWatchMark(sw)
    local integer i = 0
            loop
                set i = i + 1
                exitwhen i > 2500
                call TimerStart(CreateTimer(),0.,false,function IND)
            endloop
    // Insert code to be benchmarked here
    set t1 = StopWatchMark(sw)
    call BJDebugMsg("HandleIndexing: "+R2S(t1-t0-(settime2-settime1)))

    endfunction
    endlibrary
     






    And a manual, how to improve coding with HandleIndexing:
    Manual

    Code (vJASS):

    How do I use this perfectly?

        If You want attach Data to many handles at the same time,
        dont create a new Index for each handle. Create one index
        for a handle and use this one for the others, too.
       
        Use this in combination with Recycling. Then you can attach
        the data to a recycled handle.
       
        If you have private globals, you should better use CCComfort.
        CCComfort converts a string into a unique integer.
        You can use that int as index.
       
        Note, that FlusIndex(handle) returns the index of the handle.
        So, if you want perfect performance when you Flush Data, you
        should do this:
       
            local integer index = FlushIndex(handle)
            set YourData[index] = 0
            set YourString[index] = ""
            set YourUnit[index] = null
           
            ===> This is for a better performance, because if you dont
                 clear globals you use with HandleIndexing, they suck
                 memory all the time.
                 
                 
        I dont know why, but this:
           
            debug if ( hashnum > MAX_HANDLE_ID_COUNT ) then
            debug call BJDebugMsg("Handle Indexes; Index of handle too big. Increae 'MAX_HANDLE_ID_COUNT'!")
            debug endif
       
        costs a lot of performance. If you know, that HandleIndexing works, remove this.
     
     
    Last edited: Mar 6, 2009
  2. Deaod

    Deaod

    Joined:
    Nov 18, 2007
    Messages:
    805
    Resources:
    12
    Maps:
    1
    Spells:
    11
    Resources:
    12
    So, this system is actually slower than PUI? If yes, then why do you submit it anyway? Especially since theres CSData already.
    Also:
    return GetRandomInt(1,8190)
    is NOTHING you should EVER do! This is fucking insane.
    And:
    Code (vJASS):
    if IDs > 8190 then
                    debug call BJDebugMsg("Handle Indexing; Created too many Indexes! Don't forget to call ReleaseIndex(handle). Trying to fix Issue. May cause Errors or bugs!"
                    return GetRandomInt(1,8190)
                    endif
    the
    debug
    line errors.

    the Preload function in your textmacro thingy should be correctly scoped (private).
     
  3. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    First of all,
    Thank you for posting.
    After the Debug line, I forgot the brackets.
    Ill change it, but I got to see the next Uri Geller now :)D What a crap!)
    Ill also change the return GetRandomInt(1,8190).

    This system is not slower than PUI, it is as fast as PUI.
    When you remove the if Indexes > 8190 'Safety lines', this is slightly faster than PUI. But thats almost no difference. If you keep it, PUI is slightly faster.
    (Test Results: HandleIndexing: 0.011 PUI: 0.012)
    The reason why I made it, is that it works for each Handle Type and returns Indexes, you don't have to run textmacros (like with HSAS).

    The Index Remover for units of this is dynamic, so it can be faster than PUI, but not always.

    Ill scope the Preloader. Thanks for the tip.
     
  4. Vexorian

    Vexorian

    Joined:
    Mar 11, 2004
    Messages:
    649
    Resources:
    1
    Maps:
    1
    Resources:
    1
    Is there any reason to use indexing on anything other than units and items? Or to need attaching on anything other than timers? I mean, really... Is there any reason at ALL for this non-sense? Really...
     
  5. Dynasti

    Dynasti

    Joined:
    Oct 18, 2007
    Messages:
    871
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    it looks like a badly made cnp mod
     
  6. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    What's CNP?
    Maybe someone could need this...
    Who knows?
     
  7. Dynasti

    Dynasti

    Joined:
    Oct 18, 2007
    Messages:
    871
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    cnp = Copy'n paste

    ?
    Truly you seem to not know to much :p
     
  8. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    I didn't copy and paste this :)
    Do you know any similar systems?
     
  9. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    Ok. I updated both Systems.
    Recycling preloads always 5 handles now, and if the stack is empty, its size is increased automatically.
     
  10. Element of Water

    Element of Water

    Joined:
    Aug 3, 2008
    Messages:
    2,298
    Resources:
    5
    Spells:
    3
    Tutorials:
    1
    JASS:
    1
    Resources:
    5
    What's the point in this? You only ever need to recycle timers, and maybe groups (but you can always use one global group), and there are loads of other systems out there which assign unique indexes to units... this is just pointless...
     
  11. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    It's better to recycle everything... Then your hanlde IDs will never get too high.

    This is not just for unique unit Indexes. It's for handles.
    Why is it bad? You needn't use that feature, since this is as fast as other Unit Indexing systems.
     
  12. Element of Water

    Element of Water

    Joined:
    Aug 3, 2008
    Messages:
    2,298
    Resources:
    5
    Spells:
    3
    Tutorials:
    1
    JASS:
    1
    Resources:
    5
    You don't get what I'm saying. Most handles can't be cleared completely - and recycling a handle is only useful if it can be completely cleared.

    And I know it's not just for units. Other systems can make unique ids for any handle. All you need to do is take 0x100000 off it's handle id...
     
  13. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    But then you have to run textmacros for every usage. And each macro creates about 30 globals.
     
  14. Element of Water

    Element of Water

    Joined:
    Aug 3, 2008
    Messages:
    2,298
    Resources:
    5
    Spells:
    3
    Tutorials:
    1
    JASS:
    1
    Resources:
    5
    No... you don't. You just use H2I on the handle, no matter what type it is... geez...
     
  15. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    Ye, but for each Usage you have to create an Extended array, because otherwise the Handle ID's are too big.
    If you don't create extended arrays then, the Data get overwrited when used in more than one system.
     
  16. Element of Water

    Element of Water

    Joined:
    Aug 3, 2008
    Messages:
    2,298
    Resources:
    5
    Spells:
    3
    Tutorials:
    1
    JASS:
    1
    Resources:
    5
    Oh, and yours is better how?
     
  17. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    Just think:
    I create Indexes for handles!
    You can use these Indexes without running textmacros, because the system is supposed to have that feature!
    The Indexes are in a range between 1 and 8190.. So I attach the Indexes to the Handle, instead of direct Data.
    ==> Doesn't make it much slower, but you don't have to run textmacros and create a lot of globals.
     
  18. Element of Water

    Element of Water

    Joined:
    Aug 3, 2008
    Messages:
    2,298
    Resources:
    5
    Spells:
    3
    Tutorials:
    1
    JASS:
    1
    Resources:
    5
    Code (vJASS):

    function H2I takes handle h returns integer
        return 0
        return null
    endfunction

    function GetUniqueIndex takes handle h returns integer
        return H2I(h)-0x100000
    endfunction
    Oh look, I can get unique id's for units!
     
  19. MapperMalte

    MapperMalte

    Joined:
    Nov 4, 2007
    Messages:
    326
    Resources:
    5
    Maps:
    2
    Spells:
    2
    JASS:
    1
    Resources:
    5
    That is not a unique ID for a unit. The ID has to be between 1 and 8190.
    Just read the code.
    You don't seem to understand.
    If you use this way of getting unique Indexes, the filled arrays need a size of whatever, maxbe 300000.
    And that creates a lot of other globals, because that's a feature of the NewGen.
    And with higher IDs, it gets a looot slower.
    If the H2I value - 0x100000 of the unit is for example 185555, you have to run thorugh
    22 Ifs.

    The Method I use, converts a high Index, into an index bewtween 1 and 8190 ==> No use for extended Arrays with size e.g 100000.

    Extended arrays are _Non-real-arrays_!
    The size of a real array is 8190!







    Edit: OK. You don't seem to understand!
    Let me expalin again.

    The Handle IDs of handles is 0x0000000 + counter.
    Every time you create a handle, the counter is increased by 1.
    So if the counter is higher than 8190, it fits no longer into an array, because
    the biggest Index for an array is 8190.
    So if you use the HANDLEID-0x000000 method, you need bigger arrays than 8190.
    And there is the solution: The JassHelper has a feature called extended arrays.
    Extended arrays create arrays that have more space than 8190 IDs.
    But they aren't real arrays.
    If I write

    globals
    integer array Data [300000] ==> For an array with a space of 300000
    endglobals

    the JassHelper makes the following code from it:
    Code (vJASS):

    //JASSHelper struct globals:
    integer array s__Data
    integer array s__2Data
    integer array s__3Data
    integer array s__4Data
    integer array s__5Data
    integer array s__6Data
    integer array s__7Data
    integer array s__8Data
    integer array s__9Data
    integer array s__10Data
    integer array s__11Data
    integer array s__12Data
    integer array s__13Data
    integer array s__14Data
    integer array s__15Data
    integer array s__16Data
    integer array s__17Data
    integer array s__18Data
    integer array s__19Data
    integer array s__20Data
    integer array s__21Data
    integer array s__22Data
    integer array s__23Data
    integer array s__24Data
    integer array s__25Data
    integer array s__26Data
    integer array s__27Data
    integer array s__28Data
    integer array s__29Data
    integer array s__30Data
    integer array s__31Data
    integer array s__32Data
    integer array s__33Data
    integer array s__34Data
    integer array s__35Data
    integer array s__36Data
    integer array s__37Data

    endglobals

    function sg__Data_get takes integer i returns integer
        if(i<8191) then
            return s__Data[i]
        elseif(i<16382) then
            return s__2Data[i-8191]
        elseif(i<24573) then
            return s__3Data[i-16382]
        elseif(i<163820) then
            if(i<32764) then
                return s__4Data[i-24573]
            elseif(i<40955) then
                return s__5Data[i-32764]
            elseif(i<49146) then
                return s__6Data[i-40955]
            elseif(i<106483) then
                if(i<57337) then
                    return s__7Data[i-49146]
                elseif(i<65528) then
                    return s__8Data[i-57337]
                elseif(i<73719) then
                    return s__9Data[i-65528]
                elseif(i<90101) then
                    if(i<81910) then
                        return s__10Data[i-73719]
                    else
                        return s__11Data[i-81910]
                    endif
                else
                    if(i<98292) then
                        return s__12Data[i-90101]
                    else
                        return s__13Data[i-98292]
                    endif
                endif
            else
                if(i<114674) then
                    return s__14Data[i-106483]
                elseif(i<122865) then
                    return s__15Data[i-114674]
                elseif(i<131056) then
                    return s__16Data[i-122865]
                elseif(i<147438) then
                    if(i<139247) then
                        return s__17Data[i-131056]
                    else
                        return s__18Data[i-139247]
                    endif
                else
                    if(i<155629) then
                        return s__19Data[i-147438]
                    else
                        return s__20Data[i-155629]
                    endif
                endif
            endif
        else
            if(i<172011) then
                return s__21Data[i-163820]
            elseif(i<180202) then
                return s__22Data[i-172011]
            elseif(i<188393) then
                return s__23Data[i-180202]
            elseif(i<245730) then
                if(i<196584) then
                    return s__24Data[i-188393]
                elseif(i<204775) then
                    return s__25Data[i-196584]
                elseif(i<212966) then
                    return s__26Data[i-204775]
                elseif(i<229348) then
                    if(i<221157) then
                        return s__27Data[i-212966]
                    else
                        return s__28Data[i-221157]
                    endif
                else
                    if(i<237539) then
                        return s__29Data[i-229348]
                    else
                        return s__30Data[i-237539]
                    endif
                endif
            else
                if(i<253921) then
                    return s__31Data[i-245730]
                elseif(i<262112) then
                    return s__32Data[i-253921]
                elseif(i<270303) then
                    return s__33Data[i-262112]
                elseif(i<286685) then
                    if(i<278494) then
                        return s__34Data[i-270303]
                    else
                        return s__35Data[i-278494]
                    endif
                else
                    if(i<294876) then
                        return s__36Data[i-286685]
                    else
                        return s__37Data[i-294876]
                    endif
                endif
            endif
        endif
    endfunction

    function sg__Data_set takes integer i,integer v returns nothing
        if(i<8191) then
            set s__Data[i]=v
        elseif(i<16382) then
            set s__2Data[i-8191]=v
        elseif(i<24573) then
            set s__3Data[i-16382]=v
        elseif(i<163820) then
            if(i<32764) then
                set s__4Data[i-24573]=v
            elseif(i<40955) then
                set s__5Data[i-32764]=v
            elseif(i<49146) then
                set s__6Data[i-40955]=v
            elseif(i<106483) then
                if(i<57337) then
                    set s__7Data[i-49146]=v
                elseif(i<65528) then
                    set s__8Data[i-57337]=v
                elseif(i<73719) then
                    set s__9Data[i-65528]=v
                elseif(i<90101) then
                    if(i<81910) then
                        set s__10Data[i-73719]=v
                    else
                        set s__11Data[i-81910]=v
                    endif
                else
                    if(i<98292) then
                        set s__12Data[i-90101]=v
                    else
                        set s__13Data[i-98292]=v
                    endif
                endif
            else
                if(i<114674) then
                    set s__14Data[i-106483]=v
                elseif(i<122865) then
                    set s__15Data[i-114674]=v
                elseif(i<131056) then
                    set s__16Data[i-122865]=v
                elseif(i<147438) then
                    if(i<139247) then
                        set s__17Data[i-131056]=v
                    else
                        set s__18Data[i-139247]=v
                    endif
                else
                    if(i<155629) then
                        set s__19Data[i-147438]=v
                    else
                        set s__20Data[i-155629]=v
                    endif
                endif
            endif
        else
            if(i<172011) then
                set s__21Data[i-163820]=v
            elseif(i<180202) then
                set s__22Data[i-172011]=v
            elseif(i<188393) then
                set s__23Data[i-180202]=v
            elseif(i<245730) then
                if(i<196584) then
                    set s__24Data[i-188393]=v
                elseif(i<204775) then
                    set s__25Data[i-196584]=v
                elseif(i<212966) then
                    set s__26Data[i-204775]=v
                elseif(i<229348) then
                    if(i<221157) then
                        set s__27Data[i-212966]=v
                    else
                        set s__28Data[i-221157]=v
                    endif
                else
                    if(i<237539) then
                        set s__29Data[i-229348]=v
                    else
                        set s__30Data[i-237539]=v
                    endif
                endif
            else
                if(i<253921) then
                    set s__31Data[i-245730]=v
                elseif(i<262112) then
                    set s__32Data[i-253921]=v
                elseif(i<270303) then
                    set s__33Data[i-262112]=v
                elseif(i<286685) then
                    if(i<278494) then
                        set s__34Data[i-270303]=v
                    else
                        set s__35Data[i-278494]=v
                    endif
                else
                    if(i<294876) then
                        set s__36Data[i-286685]=v
                    else
                        set s__37Data[i-294876]=v
                    endif
                endif
            endif
        endif
    endfunction
     


    If you use HandleIndexing, you only have to create one extended array.
    And the system attaches unique integers between 1 and 8190 to the unit.
    And these attached integers fit into any arrays, not just extended arrays.

    And this system is almost as fast as extended arrays.
     
  20. Element of Water

    Element of Water

    Joined:
    Aug 3, 2008
    Messages:
    2,298
    Resources:
    5
    Spells:
    3
    Tutorials:
    1
    JASS:
    1
    Resources:
    5
    Actually, extended arrays can only go up to 60000, and real arrays go up to index 8191, which is the 8192th slot (since you can have slot 0). And fine, you want a value between 0 and 8191? I'll give you one:

    Code (vJASS):
    function H2I takes handle h returns integer
        return 0
        return h
    endfunction
    function GetUniqueIndex takes handle h returns integer
        local integer i = H2I(h)
        return i - (i/8191) * 8191
    endfunction