From a769856345db7f6e5af7762006cfcb3e88ba2dde Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 13 Apr 2018 00:06:05 +0100 Subject: [PATCH] refactor(associative): add private impls for EquivMap/Set --- packages/associative/package.json | 3 + packages/associative/src/equiv-map.ts | 79 ++++++++++++++++----------- packages/associative/src/equiv-set.ts | 68 +++++++++++++---------- 3 files changed, 90 insertions(+), 60 deletions(-) diff --git a/packages/associative/package.json b/packages/associative/package.json index bacb6bfb7b..f50ca3e154 100644 --- a/packages/associative/package.json +++ b/packages/associative/package.json @@ -37,6 +37,9 @@ "join", "map", "set", + "skiplist", + "sorted map", + "sorted set", "typescript", "union" ], diff --git a/packages/associative/src/equiv-map.ts b/packages/associative/src/equiv-map.ts index 288bfc929a..baf12eb29a 100644 --- a/packages/associative/src/equiv-map.ts +++ b/packages/associative/src/equiv-map.ts @@ -4,6 +4,17 @@ import { equiv } from "@thi.ng/api/equiv"; import { SEMAPHORE, Pair } from "./api"; import { EquivSet } from "./equiv-set"; +interface EqMapProps { + keys: EquivSet; + map: Map; +} + +export interface EqMapOpts { + equiv: Predicate2; +} + +const __private = new WeakMap, EqMapProps>(); + export class EquivMap extends Map implements Iterable>, ICopy>, @@ -20,16 +31,11 @@ export class EquivMap extends Map implements return m; } - protected _keys: EquivSet; - protected _map: Map; - constructor(pairs?: Iterable>, eq: Predicate2 = equiv) { super(); - this._keys = new EquivSet(null, eq); - this._map = new Map(); - Object.defineProperties(this, { - _keys: { enumerable: false }, - _map: { enumerable: false } + __private.set(this, { + keys: new EquivSet(null, eq), + map: new Map(), }); if (pairs) { this.into(pairs); @@ -45,22 +51,26 @@ export class EquivMap extends Map implements } get size() { - return this._keys.size; + return __private.get(this).keys.size; } clear() { - this._keys.clear(); - this._map.clear(); + const $this = __private.get(this); + $this.keys.clear(); + $this.map.clear(); } empty() { - return new EquivMap(null, (this._keys)._equiv); + return new EquivMap(null, __private.get(this).keys.getOpts().equiv); } copy() { - const m = new EquivMap(null, (this._keys)._equiv); - m._keys = this._keys.copy(); - m._map = new Map(this._map); + const $this = __private.get(this); + const m = new EquivMap(); + __private.set(m, { + keys: $this.keys.copy(), + map: new Map($this.map) + }); return m; } @@ -74,8 +84,8 @@ export class EquivMap extends Map implements if (this.size !== o.size) { return false; } - for (let k of this._map.keys()) { - if (!equiv(o.get(k), this._map.get(k))) { + for (let k of __private.get(this).map.keys()) { + if (!equiv(o.get(k), __private.get(this).map.get(k))) { return false; } } @@ -83,10 +93,11 @@ export class EquivMap extends Map implements } delete(key: K) { - key = this._keys.get(key, SEMAPHORE); + const $this = __private.get(this); + key = $this.keys.get(key, SEMAPHORE); if (key !== SEMAPHORE) { - this._map.delete(key); - this._keys.delete(key); + $this.map.delete(key); + $this.keys.delete(key); return true; } return false; @@ -100,30 +111,32 @@ export class EquivMap extends Map implements } forEach(fn: (val: V, key: K, map: Map) => void, thisArg?: any) { - for (let pair of this._map) { + for (let pair of __private.get(this).map) { fn.call(thisArg, pair[1], pair[0], this); } } get(key: K, notFound?: any) { - key = this._keys.get(key, SEMAPHORE); + const $this = __private.get(this); + key = $this.keys.get(key, SEMAPHORE); if (key !== SEMAPHORE) { - return this._map.get(key); + return $this.map.get(key); } return notFound; } has(key: K) { - return this._keys.has(key); + return __private.get(this).keys.has(key); } set(key: K, value: V) { - const k = this._keys.get(key, SEMAPHORE); + const $this = __private.get(this); + const k = $this.keys.get(key, SEMAPHORE); if (k !== SEMAPHORE) { - this._map.set(k, value); + $this.map.set(k, value); } else { - this._keys.add(key); - this._map.set(key, value); + $this.keys.add(key); + $this.map.set(key, value); } return this; } @@ -136,14 +149,18 @@ export class EquivMap extends Map implements } entries() { - return this._map.entries(); + return __private.get(this).map.entries(); } keys() { - return this._map.keys(); + return __private.get(this).map.keys(); } values() { - return this._map.values(); + return __private.get(this).map.values(); + } + + getOpts(): EqMapOpts { + return __private.get(this).keys.getOpts(); } } \ No newline at end of file diff --git a/packages/associative/src/equiv-set.ts b/packages/associative/src/equiv-set.ts index 6d351a97a5..175499f13b 100644 --- a/packages/associative/src/equiv-set.ts +++ b/packages/associative/src/equiv-set.ts @@ -1,7 +1,18 @@ import { ICopy, IEmpty, IEquiv, Predicate2 } from "@thi.ng/api/api"; import { equiv } from "@thi.ng/api/equiv"; import { DCons } from "@thi.ng/dcons"; -import { SEMAPHORE } from "./api"; +import { SEMAPHORE, Pair } from "./api"; + +interface EqSetProps { + vals: DCons; + equiv: Predicate2; +} + +export interface EqSetOpts { + equiv: Predicate2; +} + +const __private = new WeakMap, EqSetProps>(); /** * An alternative set implementation to the native ES6 Set type. Uses @@ -18,22 +29,14 @@ export class EquivSet extends Set implements IEmpty>, IEquiv { - protected _vals: DCons; - protected _equiv: Predicate2; - constructor(vals?: Iterable, eq: Predicate2 = equiv) { super(); - this._equiv = eq; - this._vals = new DCons(); - Object.defineProperties(this, { - _vals: { enumerable: false }, - _equiv: { enumerable: false } - }); + __private.set(this, { equiv: eq, vals: new DCons() }); vals && this.into(vals); } *[Symbol.iterator]() { - yield* this._vals; + yield* __private.get(this).vals; } get [Symbol.species]() { @@ -41,31 +44,32 @@ export class EquivSet extends Set implements } get size() { - return this._vals.length; + return __private.get(this).vals.length; } copy() { - const s = new EquivSet(null, this._equiv); - s._vals = this._vals.copy(); + const $this = __private.get(this); + const s = new EquivSet(null, $this.equiv); + __private.get(s).vals = $this.vals.copy(); return s; } empty() { - return new EquivSet(null, this._equiv); + return new EquivSet(null, __private.get(this).equiv); } clear() { - this._vals.clear(); + __private.get(this).vals.clear(); } first() { if (this.size) { - return this._vals.head.value; + return __private.get(this).vals.head.value; } } add(x: T) { - !this.has(x) && this._vals.push(x); + !this.has(x) && __private.get(this).vals.push(x); return this; } @@ -88,8 +92,9 @@ export class EquivSet extends Set implements * @param notFound */ get(x: T, notFound?: any) { - const eq = this._equiv; - let i = this._vals.head; + const $this = __private.get(this); + const eq = $this.equiv; + let i = $this.vals.head; while (i) { if (eq(i.value, x)) { return i.value; @@ -100,11 +105,12 @@ export class EquivSet extends Set implements } delete(x: T) { - const eq = this._equiv; - let i = this._vals.head; + const $this = __private.get(this) + const eq = $this.equiv; + let i = $this.vals.head; while (i) { if (eq(i.value, x)) { - this._vals.splice(i, 1); + $this.vals.splice(i, 1); return true; } i = i.next; @@ -129,7 +135,7 @@ export class EquivSet extends Set implements if (this.size !== o.size) { return false; } - let i = this._vals.head; + let i = __private.get(this).vals.head; while (i) { if (!o.has(i.value)) { return false; @@ -140,24 +146,28 @@ export class EquivSet extends Set implements } forEach(fn: (val: T, val2: T, set: Set) => void, thisArg?: any) { - let i = this._vals.head; + let i = __private.get(this).vals.head; while (i) { fn.call(thisArg, i.value, i.value, this); i = i.next; } } - *entries(): IterableIterator<[T, T]> { - for (let v of this._vals) { + *entries(): IterableIterator> { + for (let v of __private.get(this).vals) { yield [v, v]; } } *keys() { - yield* this._vals; + yield* __private.get(this).vals; } *values() { - yield* this._vals; + yield* this.keys(); + } + + getOpts(): EqSetOpts { + return { equiv: __private.get(this).equiv }; } }