Skip to content

Commit c19d007

Browse files
feat(common): Add onEvict() callback registry for queues with max length
1 parent b95b0ca commit c19d007

File tree

2 files changed

+118
-2
lines changed

2 files changed

+118
-2
lines changed

src/common/queue.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
1+
import { pushTo } from './common';
2+
13
/**
24
* @module common
3-
*/ /** for typedoc */
5+
*/
6+
/** for typedoc */
47

58
export class Queue<T> {
9+
private _evictListeners: ((item: T) => void)[] = [];
10+
public onEvict = pushTo(this._evictListeners);
11+
612
constructor(private _items: T[] = [], private _limit: number = null) { }
713

814
enqueue(item: T) {
915
const items = this._items;
1016
items.push(item);
11-
if (this._limit && items.length > this._limit) items.shift();
17+
if (this._limit && items.length > this._limit) this.evict();
18+
return item;
19+
}
20+
21+
evict(): T {
22+
const item: T = this._items.shift();
23+
this._evictListeners.forEach(fn => fn(item));
1224
return item;
1325
}
1426

test/commonSpec.ts

+104
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
defaults, filter, is, eq, not, pattern, val, isInjectable,
33
} from '../src/index';
44
import { map, mapObj, pick } from '../src/common/common';
5+
import { Queue } from '../src/common';
56

67
describe('common', function() {
78
describe('filter', function() {
@@ -162,4 +163,107 @@ describe('common', function() {
162163
expect(dest).toEqual({ foo: 2, bar: 4, baz: 6 });
163164
});
164165
});
166+
167+
describe('Queue', () => {
168+
it('peekTail() should show the last enqueued item', () => {
169+
const q = new Queue();
170+
q.enqueue(1);
171+
q.enqueue(2);
172+
q.enqueue(3);
173+
expect(q.size()).toBe(3);
174+
expect(q.peekTail()).toBe(3);
175+
});
176+
177+
it('peekHead() should show the first enqueued item', () => {
178+
const q = new Queue();
179+
q.enqueue(1);
180+
q.enqueue(2);
181+
q.enqueue(3);
182+
expect(q.size()).toBe(3);
183+
expect(q.peekHead()).toBe(1);
184+
});
185+
186+
it('should support a limit (max number of items)', () => {
187+
const q = new Queue([], 2);
188+
q.enqueue(1);
189+
q.enqueue(2);
190+
q.enqueue(3);
191+
expect(q.size()).toBe(2);
192+
expect(q.peekHead()).toBe(2);
193+
expect(q.peekTail()).toBe(3);
194+
});
195+
196+
it('clear() should remove all items', () => {
197+
const q = new Queue([], 2);
198+
q.enqueue(1);
199+
q.enqueue(2);
200+
q.enqueue(3);
201+
expect(q.size()).toBe(2);
202+
203+
q.clear();
204+
expect(q.size()).toBe(0);
205+
});
206+
207+
it('enqueue() should evict from the head when max length is reached', () => {
208+
const q = new Queue([], 3);
209+
q.enqueue(1);
210+
q.enqueue(2);
211+
q.enqueue(3);
212+
expect(q.size()).toBe(3);
213+
214+
q.enqueue(4);
215+
expect(q.size()).toBe(3);
216+
217+
const a = q.dequeue();
218+
const b = q.dequeue();
219+
const c = q.dequeue();
220+
221+
expect(q.size()).toBe(0);
222+
expect([a, b, c]).toEqual([2, 3, 4]);
223+
});
224+
225+
it('onEvict() handlers should be called when an item is evicted', () => {
226+
const log = [];
227+
const q = new Queue([], 2);
228+
229+
q.onEvict(item => log.push(item));
230+
231+
q.enqueue(1);
232+
expect(q.size()).toBe(1);
233+
expect(log).toEqual([]);
234+
235+
q.enqueue(2);
236+
expect(q.size()).toBe(2);
237+
expect(log).toEqual([]);
238+
239+
q.enqueue(3);
240+
expect(q.size()).toBe(2);
241+
expect(log).toEqual([1]);
242+
243+
q.enqueue(4);
244+
expect(q.size()).toBe(2);
245+
expect(log).toEqual([1, 2]);
246+
});
247+
248+
it('onEvict() should support multiple handlers', () => {
249+
const log = [];
250+
const log2 = [];
251+
const q = new Queue([], 2);
252+
253+
q.onEvict(item => log.push(item));
254+
q.onEvict(item => log2.push(item));
255+
256+
q.enqueue(1);
257+
q.enqueue(2);
258+
q.enqueue(3);
259+
expect(q.size()).toBe(2);
260+
expect(log).toEqual([1]);
261+
expect(log2).toEqual([1]);
262+
263+
q.enqueue(4);
264+
expect(q.size()).toBe(2);
265+
expect(log).toEqual([1, 2]);
266+
expect(log2).toEqual([1, 2]);
267+
});
268+
});
165269
});

0 commit comments

Comments
 (0)