• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Instance Iterator

Level 20
Joined
Jul 6, 2009
Messages
1,885
So, well. I've updated it following Nestharus' advices although there's maybe space for more improvement.
It's an improved version of T32.
JASS:
library II //Instance Iterator 1.1.0.1 by Garfield1337
    
//    Iterates struct instances, for more info, check T32:
//    [url]http://www.thehelper.net/forums/showthread.php/132538-Timer32[/url]
    
//    Usage:
//    -Implement II module
//    -Add a method named "periodic" above the module implementation that doesn't
//     take any arguments, this method will be called each iteration
//    -call start() method to start iterating an instance
//    -call end() method to stop

    globals
        private trigger t = CreateTrigger()
        private integer C = 0 //Global instance count
        private timer m = CreateTimer()
    endglobals
    
    private function e takes nothing returns nothing
        call TriggerEvaluate(t)
    endfunction

    module II
        private static boolexpr b
        private static triggercondition d
        private thistype n //next
        private thistype p //previous
        private integer c //Struct's instance count
        
        private static method l takes nothing returns boolean
            local thistype this=thistype(0).n
            loop
                exitwhen 0==this
                call .periodic()
                set this=.n
            endloop
            return false
        endmethod
        
        method start takes nothing returns nothing
            if 0==C then
                call TimerStart(m,0.031250000,true,function e) //ResumeTimer() doesn't seem to work on a looping timer
                set .d=TriggerAddCondition(t,.b)
            elseif 0==.c then
                set .d=TriggerAddCondition(t,.b)
            endif
            set C=C+1
            set .c=.c+1
            set thistype(0).n.p=this
            set .n=thistype(0).n
            set thistype(0).n=this
            set .p=thistype(0)
        endmethod
        
        method end takes nothing returns nothing
            set C=C-1
            set .c=.c-1
            if 0==C then
                call PauseTimer(m)
                call TriggerClearConditions(t)
            elseif 0==.c then
                call TriggerRemoveCondition(t,.d)
            endif
            set .p.n=.n
            set .n.p=.p
        endmethod
        
        private static method onInit takes nothing returns nothing
            set .b=Condition(function thistype.l)
            set .d=TriggerAddCondition(t,.b)
        endmethod
    
    endmodule

endlibrary
I didn't really like T32's Tick, kinda long method names and the fact J4L doesn't pause the timer so i made this.
 
Last edited:

BBQ

BBQ

Level 4
Joined
Jun 7, 2011
Messages
97
Here's a small improvement.
JASS:
        method end takes nothing returns nothing
            set C = C - 1
            if C == 0 then
                call PauseTimer(l)
            elseif .i != .c then //If the instance is not last in the array, the last one is moved to it position
                set .I[.i] = .I[.c]
                set .I[.i].i = .i            
            endif
			set .c = .c - 1
        endmethod
And for sanity's sake... name your stuff properly. Also, think of a more adequate name to use instead of execute. .execute() and .evaluate() are kind of "reserved" for different stuff.

Furthermore, your module's members should be declared private.
 
JASS:
        method start takes nothing returns nothing
            if C == 0 then
                call TimerStart(l,0.031250000,true,function e) //ResumeTimer() doesn't seem to work on a looping timer
            endif
            set C=C+1
            set .c=.c+1
            set .I[.c]=this
            set .i=.c
        endmethod
        
        method end takes nothing returns nothing
            set C=C-1
            set .c=.c-1
            if C == 0 then
                call PauseTimer(l)
            elseif .i!=.c+1 then //If the instance is not last in the array, the last one is moved to it's position
                set .I[.i] =.I[.c+1]
                set .I[.i].i=.i            
            endif
        endmethod

->

JASS:
        method start takes nothing returns nothing
            if 0==C then
                call TimerStart(l,0.031250000,true,function e)
            endif
            set C=C+1
            set .c=C
            set .I[C]=this
            set .i=C
        endmethod
        
        method end takes nothing returns nothing
            if 1==C then
                call PauseTimer(l)
            elseif .i!=C then
                set .I[.i] =.I[C]
                set .I[.i].i=.i
            endif
            set C=C-1
            set .c=C
        endmethod

That should be slightly faster :)
 

BBQ

BBQ

Level 4
Joined
Jun 7, 2011
Messages
97
How is that?
I can treat .c and C as if they were the same since whenever we increase/decrease one, the other is changed as well and they both started at 0..

thistype.c is the instance count of a specific struct, while C is the instance count of all structs in total.

Say, you have three structs, with the first one having 2 instances running the iterator, the second one 3 and the third one 4. thistype.c would equal 2, 3, 4 for the three respective structs, while C would equal 9. And last time I checked, that wasn't the same.
 
bad... recode it.


you don't need a count, the removal stuff should be in the main library, not the module. You should be using a stack since you can't remove a currently evaluating trigger condition from the trigger that it's on.

You don't need either of these in the module
JASS:
private static boolexpr b
        private static triggercondition d

Give the implemented module an id and store the boolexpr and triggercondition in arrays using that id, that way you can pass them more easily into a stack.

edit
And this
call .periodic()

Remove the overhead of a function call. Keep in mind that functions with many locals are very costly to call. Check out TimerUtils to see how I used 4 modules to allow declarations for locals, timer expiration, and nulling locals.
 
Level 20
Joined
Jul 6, 2009
Messages
1,885
you don't need a count, the removal stuff should be in the main library, not the module.
If i don't use a count, how would i know the number of instances oO
You don't need either of these in the module
JASS:
private static boolexpr b
        private static triggercondition d

Give the implemented module an id and store the boolexpr and triggercondition in arrays using that id, that way you can pass them more easily into a stack.
More easily? Using them as a static member is quite good imo.
Also why would i use an array for those? Don't you think it's better just a global/static member per struct?
edit
And this
call .periodic()

Remove the overhead of a function call. Keep in mind that functions with many locals are very costly to call. Check out TimerUtils to see how I used 4 modules to allow declarations for locals, timer expiration, and nulling locals.
How would i remove the overhead?
Tu's code takes time to read, mind explaining it shortly? :eek:

@Bribe
In T32 thread on TH, you mentioned declaring locals in the evaluated static method, but how would you pass those variables to the periodic method?
 
If i don't use a count, how would i know the number of instances oO

if (0==n[0]) then

More easily? Using them as a static member is quite good imo.
Also why would i use an array for those? Don't you think it's better just a global/static member?

You'll have to pass it to a stack regardless for removal, thus it's better to use an array. Furthermore, you want to minimize the amount of code a module generates as well as minimize methods and globals.

How would i remove the overhead?
Tu's code is long, mind explaining it shortly? :eek:

JASS:
library Bleh
private keyword e
private keyword i
module Local
    static method e takes nothing returns nothing
        local integer i=first
endmodule
module Expire
        loop
            exitwhen 0==i
endmodule
module Null
            set i=next[i]
        endloop
endmodule
module End
    endmethod
endmodule
endlibrary

JASS:
struct Tester extends array
    implement Local
        local string s="hi"
    implement Expire
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,s)
    implement Null
        set s=null
    implement End
endstruct

edit
n[0] is next[0]
 
Last edited:
thistype.c is the instance count of a specific struct, while C is the instance count of all structs in total.

Say, you have three structs, with the first one having 2 instances running the iterator, the second one 3 and the third one 4. thistype.c would equal 2, 3, 4 for the three respective structs, while C would equal 9. And last time I checked, that wasn't the same.

I get it now :)
 
Level 20
Joined
Jul 6, 2009
Messages
1,885
So...
If i use stack, i need to have the count variable.

Also i don't really understand the thing about overhead and modules :/

Also, what Bribe suggested about making a function that will be called every iteration, should each struct have it's own method for this? If not, how else should it be? Would be bad if it was just one function within the library, in case many structs need it, the code would be a mess.
 
Top