Code Examples for Reading 25
Download
You can also download a ZIP file containing this code.
Counter.ts
// Type of Counter's listener callback
export type NumberListener = (numberReached:bigint) => void;
/** A mutable incrementing counter that calls its listeners each time it
* reaches a new number. */
export class Counter {
private _value: bigint = 0n;
private listeners: Array<NumberListener> = [];
// Abstraction function
// AF(_value, listeners) = a counter currently at `_value`
// that sends events to the `listeners` whenever it changes
// Rep invariant
// true
/** Make a counter initially set to zero. */
public constructor() {
}
/** @return the value of this counter. */
public get value():bigint {
return this._value;
}
/** Increment this counter. */
public increment():void {
++this._value;
this.callListeners();
}
/** Modifies this counter by adding a listener.
* @param listener called by this counter when it changes. */
public addEventListener(listener: NumberListener):void {
this.listeners.push(listener);
}
/** Modifies this counter by removing a listener.
* @param listener will no longer be called by this counter. */
public removeEventListener(listener: NumberListener):void {
for (let i = 0; i < this.listeners.length; ++i) {
if (this.listeners[i] === listener) {
this.listeners.splice(i, 1);
return;
}
}
}
// Call all listeners to notify them about a new number
private callListeners():void {
// iterate over a copy of listeners so that we are re-entrant
// (i.e. a listener may call add/removeNumberListener,
// which would mutate the set in the midst of iteration)
for (const listener of [...this.listeners]) {
listener(this._value);
}
}
}
/**
* Example client code, trying out a Counter with a couple listeners.
*/
function main() {
const counter = new Counter();
// listen for multiples of 113
counter.addEventListener((value) => {
if (value % 113n === 0n) {
console.log(value, "is a multiple of 113");
}
});
// listen for 10000, then exit the process
counter.addEventListener((value) => {
if (value === 10000n) {
process.exit(0);
}
});
// crank the counter
while (true) {
counter.increment();
}
}
if (require.main === module) {
main();
}