- Joined
- Jul 10, 2007
- Messages
- 6,306
So this is it.. except that the data retrieval idea was a failure..
The problems:
- ResumeTimer is extremely slow
- The data retrieval in it was actually slower than a hashtable + get handle id read..
->
I decided to put this up here so that people could look at my little experimental timer library.
Fear not, I shall try again >: ).
My next idea involves a minimum binary heap >: o (exactly how JASS timers work except that they use <= rather than <).
The only problem with this idea is that I'd need to use the TimerGetRemaining native in order to read the timeouts /cry.
Actually... I just compared 80 timer get remaining calls to 40 hashtable + get handle id calls and the latter won by quite a bit.
I guess dynamic times in a timer system is just never going to beat hashtable + get handle id : |. It's never even going to come anywhere close.
If there is even an R2I call in there, a timer system will lose.
Anyways, if only arrays were actually arrays and JASS math wasn't so slow and R2I was just a type cast, then this would probably own 2 hashtable reads >.> (GetHandleId and LoadInteger).
But anyways, if anyone has an idea as to how to sort timers w/o the use of TimerGetRemaining, that'd be awesome.
I guess this also means that KT2 officially sucks since this one is already better.
At this line, KT2 already loses >.<
So... anywhere, here is my experimental timer system that failed if anyone wants to look ^)^.
ResumeTimer is a heavy operation (one reason for failure)
R2I is another pretty heavy operation (another reason for failure)
The problems:
- ResumeTimer is extremely slow
- The data retrieval in it was actually slower than a hashtable + get handle id read..
->
JASS:
static method operator expired takes nothing returns thistype
return l[R2I(TimerGetRemaining(GetExpiredTimer())*100+.5)]
endmethod
I decided to put this up here so that people could look at my little experimental timer library.
Fear not, I shall try again >: ).
My next idea involves a minimum binary heap >: o (exactly how JASS timers work except that they use <= rather than <).
The only problem with this idea is that I'd need to use the TimerGetRemaining native in order to read the timeouts /cry.
Actually... I just compared 80 timer get remaining calls to 40 hashtable + get handle id calls and the latter won by quite a bit.
I guess dynamic times in a timer system is just never going to beat hashtable + get handle id : |. It's never even going to come anywhere close.
If there is even an R2I call in there, a timer system will lose.
Anyways, if only arrays were actually arrays and JASS math wasn't so slow and R2I was just a type cast, then this would probably own 2 hashtable reads >.> (GetHandleId and LoadInteger).
But anyways, if anyone has an idea as to how to sort timers w/o the use of TimerGetRemaining, that'd be awesome.
I guess this also means that KT2 officially sucks since this one is already better.
At this line, KT2 already loses >.<
set t_id=R2I(TimerGetTimeout(GetExpiredTimer())*800)
So... anywhere, here is my experimental timer system that failed if anyone wants to look ^)^.
ResumeTimer is a heavy operation (one reason for failure)
R2I is another pretty heavy operation (another reason for failure)
JASS:
library Timer /* v1.0.0.0
*************************************************************************************
*
* Essentially TimerUtils
*
* Cons
* Only between 0 and 81.91 second timeouts and two decimal places
*
* No chance of merging timers
* - Merging timers (like what is done in KT2) is extremely rare. In most
* - cases it will be a timer that evaluates a trigger with the added
* - overhead of building and cleaning triggers. What this means
* - is that most of the time the timers will end up being slower
* - than standard timers.
*
* No auto restarting timer
* - The timer has to be resumed with the resume method
*
* No auto destroying timer
* - The timer has to be destroy method
*
* Pros
* Timers can be paused, restarted, and destroyed at any point
*
* Dynamic timeouts
*
* Supports fully dynamic code (like TimerStart)
*
* Data retrieval inlines
*
* No hashtable or GetHandleId calls
*
* No loops
*
************************************************************************************
*
* struct Timer extends array
*
* integer value
* - Value stored within the timer.
* readonly boolean paused
* - Signifies whether the timer is paused or not.
* readonly Timer expired
* - The timer that expired. Only accessible within the expiring timer.
*
* readonly real timeout
* - Timeout of timer
* readonly real remaining
* - Remaining time until timer expires
* readonly real elapsed
* - How long the timer has been running
*
* readonly timer timer
* - Useful for timer dialogs
* - Only read this value, do not manipulate directly!
*
* static method create takes real timeout, integer value, code callBack returns Timer
* - Creates and starts a new timer
* - Returns the new timer
* - Simmilar to StartTimer(CreateTimer())
* method destroy takes nothing returns nothing
* - Destroys timer
* - Similer to DestroyTimer
*
* method pause takes nothing returns nothing
* - Pauses timer
* - Similer to PauseTimer
* method resume takes nothing returns nothing
* - Resumes timer and restarts expired timers
* - Similar to ResumeTimer
* method start takes code callBack, real timeout returns nothing
* - Starts timer
* - Similer to TimerStart
*
************************************************************************************/
globals
private timer array t //timers
private integer c=0 //instance count
private integer array n //next
private integer array p //previous
private integer array l //list array
private boolean array e //end
private integer array r //list of node
private real array g //timeout
private integer array u //temporary list of node
endglobals
struct Timer extends array
integer value
readonly boolean paused
method operator timeout takes nothing returns real
return g[this]
endmethod
method operator remaining takes nothing returns real
return TimerGetRemaining(t[this])
endmethod
method operator elapsed takes nothing returns real
return TimerGetElapsed(t[this])
endmethod
method operator timer takes nothing returns timer
return t[this]
endmethod
static method operator expired takes nothing returns thistype
return l[R2I(TimerGetRemaining(GetExpiredTimer())*100+.5)]
endmethod
static method create takes real w, integer o, code b returns thistype
local Timer a
local integer s=R2I(w*100+.5) //head
local integer y=l[s] //list
//allocate new node
if (0==n[0]) then //new allocation
set a=c+1
set c=a
set t[a]=CreateTimer()
set a.paused=false
else //recycled allocation
set a=n[0]
set n[0]=n[a]
set u[a]=0
endif
//set values
set r[a]=s //list
set g[a]=s/100. //timeout
set a.value=o //value
//add new node to list
if (0==y) then //add to empty list
set l[s]=a
set n[a]=a
set p[a]=a
set e[a]=true
else //add to non empty list
set n[p[y]]=a
set p[a]=p[y]
set n[a]=y
set p[y]=a
endif
//start timer
call TimerStart(t[a],g[a],true,b)
call PauseTimer(t[a])
call ResumeTimer(t[a])
return a
endmethod
method destroy takes nothing returns nothing
//retrieve list
local integer s=u[this] //retrieve temporary list
if (0==s) then //retrieve regular list
set s=r[this]
endif
//remove from list
set n[p[this]]=n[this]
set p[n[this]]=p[this]
if (e[this]) then //handle head
if (e[n[this]]) then //if only node remaining, clear list
set l[s]=0
else //set next node to head
set e[n[this]]=true
set l[s]=n[this]
endif
set e[this]=false //unmark as head
endif
//deallocate
set n[this]=n[0]
set n[0]=this
//pause timer
call PauseTimer(t[this])
endmethod
method pause takes nothing returns nothing
//retrieve list
local integer s=u[this] //retrieve temporary list
local integer y
if (not paused) then //only run if the node isn't already paused
set paused=true //mark as paused
if (0==s) then //retrieve regular list
set s=r[this]
endif
//remove from list
set n[p[this]]=n[this]
set p[n[this]]=p[this]
if (e[this]) then //handle head
if (e[n[this]]) then //if only node remaining, clear list
set l[s]=0
else //set next node to head
set e[n[this]]=true
set l[s]=n[this]
endif
set e[this]=false //unmark as head
endif
//pause timer
call PauseTimer(t[this])
//retrieve temporary list
set u[this]=R2I(TimerGetRemaining(t[this])*100+.5)
//unset list pointers (for safe destruction)
set n[this]=this
set p[this]=this
endif
endmethod
method resume takes code b returns nothing
//retrieve list
local integer s=u[this] //retrieve temporary list
local integer y //retrieve regular list
if (0==s) then
set s=r[this]
endif
set y=l[s] //retrieve first node in list
if (paused) then //add to new list
set paused=false
//add node to list
if (0==y) then //add to empty list
set l[s]=this
set n[this]=this
set p[this]=this
set e[this]=true
else //add to non empty list
set n[p[y]]=this
set p[this]=p[y]
set n[this]=y
set p[y]=this
endif
elseif (e[this]) then //push to back of list
//if e[this] is false, then resume was called
//on a timer that's still running
if (0==u[this]) then //next on current list
set e[this]=false
set e[n[this]]=true
set l[s]=n[this]
else //remove from current list (came from a temporary list)
set u[this]=0 //unmark temporary
//remove from list
set n[p[this]]=n[this]
set p[n[this]]=p[this]
if (e[this]) then //handle head
if (e[n[this]]) then //if only node remaining, clear list
set l[s]=0
else //set next node to head
set e[n[this]]=true
set l[s]=n[this]
endif
set e[this]=false //unmark as head
endif
//retrieve regular list
set s=r[this]
set y=l[s]
//add node to list
if (0==y) then //add to empty list
set l[s]=this
set n[this]=this
set p[this]=this
set e[this]=true
else //add to non empty list
set n[p[y]]=this
set p[this]=p[y]
set n[this]=y
set p[y]=this
endif
call TimerStart(t[this],g[this],false,b)
call PauseTimer(t[this])
endif
endif
//resume the timer
call ResumeTimer(t[this])
endmethod
method start takes code b, real w returns nothing
local integer y
//retrieve list
local integer s=u[this] //retrieve temporary list
if (0==s) then //retrieve regular list
set s=r[this]
else
set u[this]=0 //clear out temporary (restarting)
endif
set paused=false
//remove from list
set n[p[this]]=n[this]
set p[n[this]]=p[this]
if (e[this]) then //handle head
if (e[n[this]]) then //if only node remaining, clear list
set l[s]=0
else //set next node to head
set e[n[this]]=true
set l[s]=n[this]
endif
set e[this]=false //unmark as head
endif
//retrieve new list
set s=R2I(w*100+.5) //list index
set y=l[s] //first node in list
//add node to list
if (0==y) then //add to empty list
set l[s]=this
set n[this]=this
set p[this]=this
set e[this]=true
else //add to non empty list
set n[p[y]]=this
set p[this]=p[y]
set n[this]=y
set p[y]=this
endif
//update values
set r[this]=s //list
set g[this]=s/100. //timeout
//start timer using new timeout
call TimerStart(t[this],g[this],false,b)
call PauseTimer(t[this])
call ResumeTimer(t[this])
endmethod
endstruct
endlibrary