| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | export class SyncableMap<K, V> extends Map<K, V> { |
| | private subscriptions = new Set<() => void>(); |
| | private lastSnapshot: Map<K, V> | null = null; |
| |
|
| | constructor(entries?: readonly (readonly [K, V])[] | null) { |
| | super(entries); |
| | } |
| |
|
| | set = (key: K, value: V): this => { |
| | super.set(key, value); |
| | this.notifySubscribers(); |
| | return this; |
| | }; |
| |
|
| | delete = (key: K): boolean => { |
| | const result = super.delete(key); |
| | this.notifySubscribers(); |
| | return result; |
| | }; |
| |
|
| | clear = (): void => { |
| | super.clear(); |
| | this.notifySubscribers(); |
| | }; |
| |
|
| | |
| | |
| | |
| | private notifySubscribers = () => { |
| | for (const callback of this.subscriptions) { |
| | callback(); |
| | } |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | subscribe = (callback: () => void): (() => void) => { |
| | this.subscriptions.add(callback); |
| | return () => { |
| | this.subscriptions.delete(callback); |
| | }; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | getSnapshot = (): Map<K, V> => { |
| | const currentSnapshot = new Map(this); |
| | if (!this.lastSnapshot || !this.areSnapshotsEqual(this.lastSnapshot, currentSnapshot)) { |
| | this.lastSnapshot = currentSnapshot; |
| | } |
| |
|
| | return this.lastSnapshot; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | private areSnapshotsEqual = (snapshotA: Map<K, V>, snapshotB: Map<K, V>): boolean => { |
| | if (snapshotA.size !== snapshotB.size) { |
| | return false; |
| | } |
| |
|
| | for (const [key, value] of snapshotA) { |
| | if (!Object.is(value, snapshotB.get(key))) { |
| | return false; |
| | } |
| | } |
| |
|
| | return true; |
| | }; |
| | } |
| |
|