UNPKG

shared-updated

Version:

Modern fork of shared (Kevin Jones), updated for latest Node.js and MongoDB

263 lines (220 loc) 6.36 kB
// Copyright (c) Kevin Jones. All rights reserved. Licensed under the Apache // License, Version 2.0. See LICENSE.txt in the project root for complete // license information. /// <reference path='import.ts' /> /// <reference path='utils.ts' /> /// <reference path='debug.ts' /> module shared { export module utils { var Tree = require('bintrees').RBTree; interface MapEntry { key: any; value: any; } interface MapRow { hash: number; values: MapEntry[]; } export class Map { private _hashfn : (a:any) => number; private _size: number; private _tree; constructor(hashfn: (a:any) => number) { dassert(isValue(hashfn)); this._size = 0; this._hashfn = hashfn; this._tree = new Tree(function (a:MapRow, b:MapRow) { return a.hash - b.hash; }); } size(): number { return this._size; } find(key: any) : any { dassert(isValue(key)); var h = this._hashfn(key); var entries: MapRow = this._tree.find({ hash: h }); if (entries !== null) { for (var i = 0; i < entries.values.length; i++) { if (isEqual(key, entries.values[i].key)) { return entries.values[i].value; } } } return null; } insert(key: any, value: any) : bool { dassert(isValue(key)); dassert(isValue(value)); var h = this._hashfn(key); var entries: MapRow = this._tree.find({ hash: h }); if (entries !== null) { var free = null; for (var i = 0; i < entries.values.length; i++) { if (entries.values[i].key === null) { if (free === null) free = i; } else if (isEqual(key, entries.values[i].key)) { return false; } } if (free !== null) entries.values[free] = { key: key, value: value }; else entries.values.push({ key: key, value: value }); } else { this._tree.insert({ hash: h, values: [{ key: key, value: value }] } ); } this._size++; return true; } findOrInsert(key: any, proto? = {}): any { var val = this.find(key); if (val !== null) { return val; } else { this.insert(key, proto); return proto; } } remove(key: any) : bool { dassert(isValue(key)); var h = this._hashfn(key); var entries: MapRow = this._tree.find({ hash: h }); if (entries !== null) { var found = true; for (var i = 0; i < entries.values.length; i++) { if (isEqual(key, entries.values[i].key)) { entries.values[i].key = null; entries.values[i].value = null; this._size--; return true; } } } return false; } apply(handler : (key: any, value: any) => bool) : bool { var it = this._tree.iterator(); while (it.next()) { var row: MapRow = it.data(); for (var i = 0; i < row.values.length; i++) { if (row.values[i].key !== null) if (handler(row.values[i].key,row.values[i].value) === false) return false; } } return true; } removeAll() : void { this._tree.clear(); this._size = 0; } } /** * A simple string set */ export class StringSet { private _map : Map; private _id: number; constructor (names: string[]=[]) { this._map = new Map(function (k: any) { return utils.hash(k.toString()); }); this._id = 0; for (var i = 0; i < names.length; i++) { this.put(names[i]); } } put(key: string): bool { var ok = this._map.insert(key, this._id); if (ok) this._id++; return ok; } has(key: string): bool { return this._map.find(key) !== null; } id(key: string): number { return this._map.find(key); } remove(key: string): bool { return this._map.remove(key); } size(): number { return this._map.size(); } removeAll(): void { return this._map.removeAll(); } apply(handler: (value: any) => bool): bool { return this._map.apply(function (key: any, value: any) { return handler(key); }); } } /** * A simple queue, items can be added/removed from the * head/tail with random access and assertions thrown in. */ export class Queue { private _elems = []; size(): number { return this._elems.length; } empty(): bool { return this.size() === 0; } front(): any { return this.at(0); } back(): any { return this.at(this.size()-1); } at(i: number) { dassert(i >= 0 && i < this.size()); return this._elems[i]; } setAt(i: number, value: any) { dassert(i >= 0 && i < this.size()); this._elems[i] = value; } push(value: any) : void { this._elems.push(value); } pop() : any { dassert(!this.empty()); return this._elems.pop(); } unshift(value: any) : void { this._elems.unshift(value); } shift() : any { dassert(!this.empty()); return this._elems.shift(); } array(): any[] { return this._elems; } first( match: (value:any) => bool): any { for (var i = 0; i < this._elems.length; i++) { if (match(this._elems[i])) return this._elems[i]; } return null; } filter( match: (value:any) => bool): Queue { var matched = new Queue(); for (var i = 0; i < this._elems.length; i++) { if (match(this._elems[i])) matched.push(this._elems[i]); } return matched; } apply( func: (value:any) => void): void { for (var i = 0; i < this._elems.length; i++) { func(this._elems[i]); } } } } // module utils } // module shared