Category : Files from Magazines
Archive   : DDJ9210.ZIP
Filename : TMDCBK.ASC

 
Output of file : TMDCBK.ASC contained in archive : DDJ9210.ZIP
_TIMED CALLBACKS IN C++_
by Christain Stapfer

[LISTING ONE]

//===== tmdcbk.hpp -- timedCallback: Interface ======
#ifndef tmdcbk_hpp
#define tmdcbk_hpp
// -- Maximum number of simultaneously queued callbacks:
#define MaxTimedCallbacks 16 // Any number > 0 will do
class timedCallback
{
public:
typedef
long (*timedCallbackFun)(timedCallback *Entry);
// Type of function to be called after a given number of tick()
// invocations.
// Return value = Number of ticks to wait till next call (0 if
// the callback must not be requeued).
timedCallback( );
// Constructs a callback using a default 'do-nothing' function.
// This allows you to create arrays of timedCallback objects and
// define the callback function later by use of member setFun().
timedCallback(timedCallbackFun SomeFun);
// Constructs a real-time clock callback to be used for later calls
// to queue() and cancel().
void queue(long Delta);
// Queues the callback to be called after the specified number of
// invocations of member tick(). Delta == 0 cancels the callback.
// Raises : NoRoom Callback queue cannot hold another entry.
// (Not implemented)
// Note : It is ok to requeue an already queued callback.
void cancel( );
// Cancels 'this' callback - if it is queued.
// Note : It is ok to cancel a callback that is not queued.

int isQueued( )
// Returns 1 if 'this' callback is queued, 0 otherwise.
{ return index != 0; }
static void tick( );
// Advances the time by one tick. Queued callbacks may time out and
// are invoked from within member tick().
void setFun(timedCallbackFun SomeFun);
// Redefines the callback function to be used for 'this' callback.
~timedCallback( )
// Cancels the callback before it goes out of scope.. .
{ cancel(); }
private:
timedCallbackFun fun; // Address of the function to be called back.
long clock;// System clock count to wait for
unsigned index;// Aux. handshake index into the heap
// Priority heap of queued callbacks is contained in:
static timedCallback *heap[MaxTimedCallbacks + 1];
static unsigned inUse;
// Number of invocations of member tick():
static long tickCount;
void upHeap( );
// Repositions 'this' heap entry if count member has been decreased
void downHeap( );
// Repositions 'this' heap entry if count member has been increased
static long defaultFun(timedCallback* );
// Default callback function used by the constructor timedCallback().
// Prevent copying of timedCallback objects:
// (You may want to modify this.. )
timedCallback(const timedCallback& );
timedCallback& operator = (const timedCallback& );
};// class timedCallback
#endif // ndef tmdcbk_hpp
// tmdcbk.hpp




[LISTING TWO]

//===== timedCallback: Implementation. timedCallback::queue() silently drops
//===== queueing requests that cannot be satisfied if the heap is already full.

#include "tmdCbk.hpp" // timedCallback interface
//#include "exc.hpp" // Exception handling (not used)

// static timedCallback data members
long timedCallback::tickCount = 0;
timedCallback *timedCallback::heap[MaxTimedCallbacks + 1];
unsigned timedCallback::inUse = 0;

// timedCallback::*() members
long timedCallback::defaultFun(timedCallback* )
// Callback used as a default for the constructor.
{
return 0;// Don't requeue
}// defaultFun()
timedCallback::timedCallback( )
{
clock = index = 0;
fun = timedCallback::defaultFun;
}// timedCallback()
timedCallback::timedCallback(timedCallbackFun SomeFun)
{
clock = index = 0;
fun = SomeFun;
}// timedCallback()
void timedCallback::setFun(timedCallbackFun SomeFun)
{
fun = SomeFun;
}// setFun()
void timedCallback::queue(long Delta)
{
long OldClock = clock;
if (Delta == 0) {
cancel();
}
else {
clock = tickCount + Delta;
if (0 < index) {
// Still queued ..
if (0 <= clock - OldClock) {
downHeap();
}
else {
upHeap();
}
}
else if (inUse < MaxTimedCallbacks) {
// Not currently queued (and there is room!)
index = inUse += 1;
heap[inUse] = this;
upHeap();
}
else {
// NoRoom.raise(); Exception handling not available!
// You may want to exit() to DOS or something.
}
}
}// queue()
void timedCallback::cancel( )
{
unsigned Index;
Index = index;
if (0 < Index) {
index = 0;
inUse -= 1;
if (Index <= inUse) {
heap[Index] = heap[inUse + 1];
heap[Index]->downHeap();
}
// else cancelling the last entry is trivial ..
}
}// cancel()
void timedCallback::tick( )
{
timedCallback **First = heap + 1;
long NewTicks;
// Advance tick count
tickCount += 1;
// Deliver timed-out callbacks
while (0 < inUse && (*First)->clock == tickCount) {
// Expired - deliver!
NewTicks = (*(*First)->fun)(*First);
if (NewTicks != 0) {
// Callback wants to be requeued
(*First)->clock = tickCount + NewTicks;
}
else {
// Callback doesn't want to be requeued
heap[inUse]->index = 1;
(*First)->index = 0;
*First = heap[inUse];
inUse -= 1;
}
if (0 < inUse) {
(*First)->downHeap();
}
}// while
}// tick()
// PRIORITY-QUEUE (HEAP) MANAGEMENT
void timedCallback::upHeap( )
{
unsigned K = index;
// Use alias as a sentinel entry to ensure we'll dropout of this loop:
heap[0] = this;
// Move 'this' up until the heap condition is satisfied again:
while (0 < heap[K >> 1]->clock - clock) {
heap[K] = heap[K >> 1];
heap[K]->index = K;
K >>= 1;
}
// Actually insert 'this' at its new position
heap[K] = this;
index = K;
}// upHeap()
void timedCallback::downHeap( )
{
unsigned J,
K = index,
Kmax = inUse >> 1;
// Scan down the heap to locate the new position for 'this':
while (K <= Kmax) {
J = K << 1;
if (J < inUse) {
if (heap[J | 1]->clock - heap[J]->clock < 0) {
J |= 1;
}
}

if (0 <= heap[J]->clock - clock)
break;
heap[K] = heap[J];
heap[K]->index = K;
K = J;
}
// Actually insert 'this' at its new position
heap[K] = this;
index = K;
}// downHeap()
// tmdcbk.cpp




[LISTING THREE]

//===== play.cpp -- Example usage of timedCallback objects: Play a tune.
//===== Compiled for MS-DOS with Borland C++.

#include "tmdcbk.hpp" // Defines timed callbacks
#include // We need sound()
#include // .. and clock()

// -- A sound is defined by the struct:
typedef struct {
unsigned freq;
unsigned delta;
} aSound; // More elaborate sounds include fading, up/down sweeps, etc.
// To create a tune we must hand it a list of sounds:
aSound List[] = { {1000,4},{0,1},{500,3},{0,1},{600,3},{0,1},
{700,1},{0,3},{700,1},{0,3},{700,4},{0,0} };
// A tune is defined as:
class tune : timedCallback {
static long PlayFun(timedCallback* Self);
aSound *toPlay;
unsigned nextSound;
public:
tune(aSound* Tune): timedCallback(tune::PlayFun)
{ toPlay = Tune; };
void play( )
{ nextSound = 0; queue(1); };
void stop( )
{ cancel(); };
private:
tune();// Only allow tune(aSound*) to be used!
};
long tune::PlayFun(timedCallback* Self)
//-- Timed callback: Walks down the list of sounds, sets the speaker
// and requeues itself accordingly until it reaches delta == 0.
{
tune *This = (tune *)Self;
aSound ThisSound = This->toPlay[This->nextSound];
if (ThisSound.freq == 0) {
nosound(); // sound(0) will not do!
}
else {
sound(ThisSound.freq);
}
if (ThisSound.delta != 0) {
This->nextSound += 1;
}
return ThisSound.delta;
}// PlayFun()
void DriveTick(unsigned Delta)
//-- Aux. function used to avoid fooling around with the clock interrupt.
{
static clock_t LastClock = 0;
for ( ; 0 < Delta ; Delta -= 1) {
while (LastClock == clock())
;// Wait till next clock tick
LastClock = clock();
timedCallback::tick();
}
}// DriveTick()
void main ( )
// Plays a single tune and quits.
{
tune Tune(List);
Tune.play(); // If we had multi-tasking we'd simply do this ..
DriveTick(50); // .. without having to drive the callbacks ourselves!
}// main()




Example 1


timedCallback AutoRepeat(RepeatFun);
assuming that you have defined the function:
long RepeatFun(timedCallback* Self)
{
// Eg. generate duplicate keypress..
return NewDelta;
}





Example 2


class context : timedCallback

{
// Whatever RepeatFun needs to know!
};
long RepeatFun(timedCallback* Self)
{
context *ContextPtr = (context *)Self;
...// Use ContextPtr->* to access data
return NewDelta;
}




Example 3:

void timedCallback::tick()
{
tickCount += 1;
if (0 <= tickCount - nextOut)
wakeUp.up();
}



  3 Responses to “Category : Files from Magazines
Archive   : DDJ9210.ZIP
Filename : TMDCBK.ASC

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/