const filterOutLinks = (k: string, v: string) => { if (k !== 'next' && k !== 'prev') { return v; } }; type LinkedNode = { prev?: LinkedNode; next?: LinkedNode; } & T; const unlink = (entry: LinkedNode) => { entry.prev!.next = entry.next; entry.next!.prev = entry.prev; delete entry.next; delete entry.prev; }; export default class List { // a shortcut that next is head and prev is tail public shortcut: LinkedNode; constructor() { const shortcut: LinkedNode = {}; shortcut.prev = shortcut; shortcut.next = shortcut.prev; this.shortcut = shortcut; } public dequeue() { const shortcut = this.shortcut; const entry = shortcut.prev; if (entry && entry !== shortcut) { unlink(entry); return entry; } } public enqueue(entry: LinkedNode) { const shortcut = this.shortcut; if (entry.prev && entry.next) { unlink(entry); } entry.next = shortcut.next; shortcut.next!.prev = entry; shortcut.next = entry; entry.prev = shortcut; } public toString() { const strs = []; const sentinel = this.shortcut; let curr = sentinel.prev; while (curr !== sentinel) { strs.push(JSON.stringify(curr, filterOutLinks)); curr = curr?.prev; } return `[${strs.join(', ')}]`; } }