Skip to content

Instantly share code, notes, and snippets.

@isthatcentered
Created October 26, 2022 18:15
Show Gist options
  • Save isthatcentered/30e41afadb5df2ca6d0245b3b901fd33 to your computer and use it in GitHub Desktop.
Save isthatcentered/30e41afadb5df2ca6d0245b3b901fd33 to your computer and use it in GitHub Desktop.
Typescript queue
describe(`Queue`, () => {
describe(`isEmpty`, () => {
test(`Empty queue returns true`, async () => {
const queue = new InMemoryQueue<string>();
const result = await queue.isEmpty();
expect(result).toEqual(true);
});
test(`Non empty queue returns false`, async () => {
const queue = new InMemoryQueue<string>();
queue.offer('some_value');
const result = await queue.isEmpty();
expect(result).toEqual(false);
});
});
describe(`take`, () => {
test(`Element already queued succeeds immediately`, async () => {
const value = 'some_value';
const queue = new InMemoryQueue<string>();
queue.offer(value);
const result = await queue.take();
expect(result).toEqual(value);
});
test(`No element queued waits until one is offered`, async () => {
const value = 'some_value';
const queue = new InMemoryQueue<string>();
const promise = queue.take();
await queue.offer(value);
expect(await promise).toEqual(value);
});
test(`Multiple pending takers each receive a different element`, async () => {
const queue = new InMemoryQueue<string>();
const promise = Promise.all([queue.take(), queue.take()]);
await queue.offer('A');
await queue.offer('B');
const [a, b] = await promise;
expect(a).toBe('A');
expect(b).toBe('B');
});
});
})
export interface ReadonlyQueue<A> {
take(): Promise<A | undefined>;
isEmpty(): Promise<boolean>;
}
export interface Queue<A> extends ReadonlyQueue<A> {
offer(value: A): Promise<void>;
}
export class InMemoryQueue<A> implements Queue<A> {
private elements: A[];
private takers: Array<(a: A) => void> = [];
constructor(elements: A[] = []) {
this.elements = elements;
}
async offer(value: A): Promise<void> {
const taker = this.takers.shift();
if (!taker) {
this.elements.push(value);
return;
}
taker(value);
}
/**
* Returns immeiately if an item is present in queue,
* waits for an element to be offered otherwise
*/
async take(): Promise<A | undefined> {
const element = this.elements.shift();
if (element) return element;
return new Promise((res) => this.takers.push(res));
}
async isEmpty(): Promise<boolean> {
return !this.elements.length;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment