twoapple-reboot/src/timer.d

244 lines
5.8 KiB
D
Raw Normal View History

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
}