import { HasGuid, ensureGuid } from './guid'; import { Option } from './platform-utils'; export interface Dict { [index: string]: T; } export interface Set { add(value: T): Set; delete(value: T): void; forEach(callback: (item: T) => void): void; } let proto = Object.create(null, { // without this, we will always still end up with (new // EmptyObject()).constructor === Object constructor: { value: undefined, enumerable: false, writable: true } }); function EmptyObject() {} EmptyObject.prototype = proto; export function dict(): Dict { // let d = Object.create(null); // d.x = 1; // delete d.x; // return d; return new (EmptyObject as any)(); } export type SetMember = HasGuid | string; export class DictSet implements Set { private dict: Dict; constructor() { this.dict = dict(); } add(obj: T): Set { if (typeof obj === 'string') this.dict[obj] = obj; else this.dict[ensureGuid(obj)] = obj; return this; } delete(obj: T) { if (typeof obj === 'string') delete this.dict[obj]; else if ((obj as any)._guid) delete this.dict[(obj as any)._guid]; } forEach(callback: (item: T) => void) { let { dict } = this; Object.keys(dict).forEach(key => callback(dict[key])); } toArray(): string[] { return Object.keys(this.dict); } } export class Stack { private stack: T[] = []; public current: Option = null; toArray(): T[] { return this.stack; } push(item: T) { this.current = item; this.stack.push(item); } pop(): Option { let item = this.stack.pop(); let len = this.stack.length; this.current = len === 0 ? null : this.stack[len - 1]; return item === undefined ? null : item; } isEmpty(): boolean { return this.stack.length === 0; } }