2012-03-14 00:43:29 +00:00
|
|
|
/+
|
|
|
|
+ timer.d
|
|
|
|
+
|
|
|
|
+ Copyright: 2007 Gerald Stocker
|
|
|
|
+
|
2012-03-15 06:21:12 +00:00
|
|
|
+ This file is part of twoapple-reboot.
|
2012-03-14 00:43:29 +00:00
|
|
|
+
|
2012-03-15 06:21:12 +00:00
|
|
|
+ twoapple-reboot is free software; you can redistribute it and/or modify
|
2012-03-14 00:43:29 +00:00
|
|
|
+ it under the terms of the GNU General Public License as published by
|
|
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
|
|
+ (at your option) any later version.
|
|
|
|
+
|
2012-03-15 06:21:12 +00:00
|
|
|
+ twoapple-reboot is distributed in the hope that it will be useful,
|
2012-03-14 00:43:29 +00:00
|
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
+ GNU General Public License for more details.
|
|
|
|
+
|
|
|
|
+ You should have received a copy of the GNU General Public License
|
2012-03-15 06:21:12 +00:00
|
|
|
+ along with twoapple-reboot; if not, write to the Free Software
|
2012-03-14 00:43:29 +00:00
|
|
|
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
+/
|
|
|
|
|
|
|
|
module timer;
|
|
|
|
|
|
|
|
class Timer
|
|
|
|
{
|
2012-03-15 06:45:30 +00:00
|
|
|
class Cycle
|
|
|
|
{
|
|
|
|
int delta;
|
|
|
|
uint rollOver;
|
|
|
|
|
|
|
|
this(uint maxVal)
|
|
|
|
{
|
|
|
|
rollOver = maxVal;
|
2012-03-14 00:43:29 +00:00
|
|
|
restart();
|
2012-03-15 06:45:30 +00:00
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
|
|
|
void restart()
|
|
|
|
{
|
2012-03-15 06:45:30 +00:00
|
|
|
delta = 0 - currentCounter.elapsed();
|
2012-03-14 00:43:29 +00:00
|
|
|
}
|
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
uint currentVal()
|
|
|
|
{
|
|
|
|
return (currentCounter.elapsed() + delta) % rollOver;
|
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
void update()
|
|
|
|
{
|
|
|
|
delta = currentVal();
|
|
|
|
}
|
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
class Counter
|
|
|
|
{
|
|
|
|
bool delegate() expiry;
|
|
|
|
uint startLength, currentLength;
|
|
|
|
int ticks;
|
2012-03-14 00:43:29 +00:00
|
|
|
bool shouldContinue;
|
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
this(uint start)
|
|
|
|
{
|
2012-03-14 00:43:29 +00:00
|
|
|
shouldContinue = true;
|
2012-03-15 06:45:30 +00:00
|
|
|
startLength = currentLength = ticks = start;
|
2012-03-14 00:43:29 +00:00
|
|
|
addCounter(this);
|
2012-03-15 06:45:30 +00:00
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
this(uint start, bool delegate() expiration)
|
|
|
|
{
|
|
|
|
this(start);
|
2012-03-14 00:43:29 +00:00
|
|
|
initCounter(this);
|
2012-03-15 06:45:30 +00:00
|
|
|
expiry = expiration;
|
|
|
|
}
|
|
|
|
|
|
|
|
final uint elapsed()
|
|
|
|
{
|
|
|
|
return currentLength - ticks;
|
|
|
|
}
|
|
|
|
|
|
|
|
final void tick()
|
|
|
|
{
|
|
|
|
--ticks;
|
|
|
|
if (ticks == 0)
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
|
|
|
final void forceExpire()
|
|
|
|
{
|
|
|
|
ticks = 1;
|
|
|
|
tick();
|
|
|
|
}
|
|
|
|
|
|
|
|
final void discard()
|
|
|
|
{
|
|
|
|
expiry = &nullExpiry;
|
|
|
|
forceExpire();
|
|
|
|
}
|
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
private final void resume()
|
|
|
|
{
|
|
|
|
currentLength = ticks;
|
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
private final bool expire()
|
|
|
|
{
|
|
|
|
ticks = currentLength = startLength;
|
|
|
|
return expiry();
|
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
|
|
|
private bool nullExpiry() { return false; }
|
2012-03-15 06:45:30 +00:00
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
class DelayedCounter : Counter
|
|
|
|
{
|
2012-03-14 00:43:29 +00:00
|
|
|
uint realStart;
|
|
|
|
bool delegate() realExpiry;
|
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
this(uint start, bool delegate() expiration, uint delay)
|
|
|
|
{
|
|
|
|
realStart = start;
|
2012-03-14 00:43:29 +00:00
|
|
|
realExpiry = expiration;
|
|
|
|
super(delay, &becomeReal);
|
2012-03-15 06:45:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private bool becomeReal()
|
|
|
|
{
|
|
|
|
ticks = currentLength = startLength = realStart;
|
|
|
|
expiry = realExpiry;
|
|
|
|
bool retval = expiry();
|
|
|
|
initCounter(this);
|
2012-03-14 00:43:29 +00:00
|
|
|
return retval;
|
2012-03-15 06:45:30 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
Cycle[] cycles;
|
|
|
|
Counter[] counters;
|
|
|
|
Counter primaryCounter, currentCounter;
|
2012-03-14 00:43:29 +00:00
|
|
|
uint hertz;
|
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
this(uint primaryStart, uint hz)
|
|
|
|
{
|
2012-03-14 00:43:29 +00:00
|
|
|
hertz = hz;
|
2012-03-15 06:45:30 +00:00
|
|
|
cycles.length = 10;
|
|
|
|
counters.length = 10;
|
|
|
|
cycles.length = 0;
|
|
|
|
counters.length = 0;
|
|
|
|
currentCounter = primaryCounter = new Counter(primaryStart);
|
|
|
|
}
|
|
|
|
|
|
|
|
final void onPrimaryStop(bool delegate() expiration)
|
|
|
|
{
|
|
|
|
primaryCounter.expiry = expiration;
|
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
|
|
|
Cycle startCycle(uint maxVal)
|
2012-03-15 06:45:30 +00:00
|
|
|
{
|
|
|
|
cycles.length = cycles.length + 1;
|
|
|
|
cycles[$-1] = new Cycle(maxVal);
|
|
|
|
return cycles[$-1];
|
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
void tick()
|
|
|
|
{
|
|
|
|
currentCounter.tick();
|
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
|
|
|
private void deleteCounters()
|
|
|
|
{
|
2012-03-14 20:29:58 +00:00
|
|
|
int numCounters = cast(int)counters.length;
|
2012-03-14 00:43:29 +00:00
|
|
|
int lastCounter;
|
|
|
|
main: for (int counter = 0; counter < counters.length; ++counter)
|
|
|
|
{
|
|
|
|
lastCounter = counter;
|
|
|
|
while (!counters[counter].shouldContinue)
|
|
|
|
{
|
|
|
|
numCounters--;
|
|
|
|
if (++counter >= counters.length) break main;
|
|
|
|
}
|
|
|
|
currentCounter = counters[lastCounter] = counters[counter];
|
|
|
|
}
|
|
|
|
if (numCounters < counters.length)
|
|
|
|
{
|
|
|
|
counters.length = numCounters;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-15 06:45:30 +00:00
|
|
|
private void addCounter(Counter newCounter)
|
|
|
|
{
|
|
|
|
counters.length = counters.length + 1;
|
|
|
|
counters[$-1] = newCounter;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void initCounter(Counter newCounter)
|
|
|
|
{
|
|
|
|
if (newCounter.ticks < currentCounter.ticks)
|
|
|
|
{
|
|
|
|
reset(newCounter);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newCounter.ticks += currentCounter.elapsed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void reset(Counter newCounter = null)
|
|
|
|
{
|
2012-03-14 00:43:29 +00:00
|
|
|
// update cycle counts
|
|
|
|
for (int cycle = 0; cycle < cycles.length; ++cycle)
|
|
|
|
{
|
|
|
|
cycles[cycle].update();
|
|
|
|
}
|
|
|
|
|
|
|
|
// update counter counts
|
|
|
|
for (int counter = 0; counter < counters.length; ++counter)
|
|
|
|
{
|
|
|
|
if (counters[counter] !is currentCounter &&
|
|
|
|
counters[counter] !is newCounter)
|
|
|
|
counters[counter].ticks -= currentCounter.elapsed();
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for expired counters
|
|
|
|
for (int counter = 0; counter < counters.length; ++counter)
|
|
|
|
{
|
|
|
|
if (counters[counter].ticks <= 0)
|
|
|
|
counters[counter].shouldContinue = counters[counter].expire();
|
|
|
|
else
|
|
|
|
counters[counter].resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
//delete counters that should be deleted
|
|
|
|
deleteCounters();
|
|
|
|
|
|
|
|
// set current counter
|
|
|
|
for (int counter = 0; counter < counters.length; ++counter)
|
|
|
|
{
|
|
|
|
if (counters[counter].ticks < currentCounter.ticks)
|
|
|
|
currentCounter = counters[counter];
|
|
|
|
}
|
2012-03-15 06:45:30 +00:00
|
|
|
}
|
2012-03-14 00:43:29 +00:00
|
|
|
|
|
|
|
}
|