1
0
Files
sequence-js/src/equality-map/impl.ts

294 lines
5.8 KiB
TypeScript

import { asAsyncEqualityComparer } from "../equality-comparer/async.js";
import { asEqualityComparer } from "../equality-comparer/sync.js";
import { AsyncEqualityComparer, EqualityComparer, EqualityComparisonOrComparer, MaybeAsyncEqualityComparisonOrComparer } from "../equality-comparer/types.js";
import { MaybeAsyncIterable } from "../types.js";
import { AsyncEqualityMap, EqualityMap, EqualityMapEntry } from "./types.js";
export class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
readonly #map = new Map<K, V>();
get size() {
return this.#map.size;
}
get(key: K) {
return this.#map.get(key);
}
set(key: K, value: V) {
const existing = this.get(key);
this.#map.set(key, value);
return existing;
}
setAll(entries: Iterable<EqualityMapEntry<K, V>>) {
for (const [key, value] of entries) {
this.set(key, value);
}
}
contains(key: K) {
return this.#map.has(key);
}
remove(key: K) {
const existing = this.get(key);
this.#map.delete(key);
return existing;
}
clear() {
this.#map.clear();
}
keys() {
return this.#map.keys();
}
values() {
return this.#map.values();
}
entries() {
return this.#map.entries();
}
[Symbol.iterator]() {
return this.#map[Symbol.iterator]();
}
}
export class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
readonly #list: EqualityMapEntry<K, V>[] = [];
readonly #keyComparer: EqualityComparer<K>;
constructor(keyComparer: EqualityComparisonOrComparer<K>) {
this.#keyComparer = asEqualityComparer(keyComparer);
}
get size() {
return this.#list.length;
}
get(key: K) {
for (const entry of this.#list) {
if (this.#keyComparer.equals(key, entry[0])) {
return entry[1];
}
}
return undefined;
}
set(key: K, value: V) {
for (const entry of this.#list) {
if (this.#keyComparer.equals(key, entry[0])) {
const previous = entry[1];
entry[1] = value;
return previous;
}
}
this.#list.push([key, value]);
return undefined;
}
setAll(entries: Iterable<EqualityMapEntry<K, V>>) {
for (const [key, value] of entries) {
this.set(key, value);
}
}
contains(key: K) {
for (const entry of this.#list) {
if (this.#keyComparer.equals(key, entry[0])) {
return true;
}
}
return false;
}
remove(key: K) {
for (let i = 0; i < this.#list.length; i++) {
if (this.#keyComparer.equals(key, this.#list[i][0])) {
const removed = this.#list.splice(i, 1);
return removed[0][1];
}
}
return undefined;
}
clear() {
this.#list.length = 0;
}
*keys() {
for (const entry of this.#list) {
yield entry[0];
}
}
*values() {
for (const entry of this.#list) {
yield entry[1];
}
}
entries() {
return this[Symbol.iterator]();
}
*[Symbol.iterator]() {
for (const entry of this.#list) {
yield entry.slice() as EqualityMapEntry<K, V>; // no entry mutation allowed!
}
}
}
export class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
readonly #map = new Map<K, V>();
get size() {
return this.#map.size;
}
async get(key: K) {
return this.#map.get(key);
}
async set(key: K, value: V) {
const existing = await this.get(key);
this.#map.set(key, value);
return existing;
}
async setAll(entries: MaybeAsyncIterable<EqualityMapEntry<K, V>>) {
for await (const [key, value] of entries) {
await this.set(key, value);
}
}
async contains(key: K) {
return this.#map.has(key);
}
async remove(key: K) {
const existing = await this.get(key);
this.#map.delete(key);
return existing;
}
clear() {
this.#map.clear();
}
keys() {
return this.#map.keys();
}
values() {
return this.#map.values();
}
entries() {
return this.#map.entries();
}
[Symbol.iterator]() {
return this.#map[Symbol.iterator]();
}
}
export class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
readonly #list: EqualityMapEntry<K, V>[] = [];
readonly #keyComparer: AsyncEqualityComparer<K>;
constructor(keyComparer: MaybeAsyncEqualityComparisonOrComparer<K>) {
this.#keyComparer = asAsyncEqualityComparer(keyComparer);
}
get size() {
return this.#list.length;
}
async get(key: K) {
for (const entry of this.#list) {
if (await this.#keyComparer.equals(key, entry[0])) {
return entry[1];
}
}
return undefined;
}
async set(key: K, value: V) {
for (const entry of this.#list) {
if (await this.#keyComparer.equals(key, entry[0])) {
const previous = entry[1];
entry[1] = value;
return previous;
}
}
this.#list.push([key, value]);
return undefined;
}
async setAll(entries: MaybeAsyncIterable<EqualityMapEntry<K, V>>) {
for await (const [key, value] of entries) {
await this.set(key, value);
}
}
async contains(key: K) {
for (const entry of this.#list) {
if (await this.#keyComparer.equals(key, entry[0])) {
return true;
}
}
return false;
}
async remove(key: K) {
for (let i = 0; i < this.#list.length; i++) {
if (await this.#keyComparer.equals(key, this.#list[i][0])) {
const removed = this.#list.splice(i, 1);
return removed[0][1];
}
}
return undefined;
}
clear() {
this.#list.length = 0;
}
*keys() {
for (const entry of this.#list) {
yield entry[0];
}
}
*values() {
for (const entry of this.#list) {
yield entry[1];
}
}
entries() {
return this[Symbol.iterator]();
}
*[Symbol.iterator]() {
for (const entry of this.#list) {
yield entry.slice() as EqualityMapEntry<K, V>; // no entry mutation allowed!
}
}
}