All files / collections/src abstractMultiMap.ts

82.6% Statements 19/23
71.42% Branches 5/7
80% Functions 12/15
80.95% Lines 17/21

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 833x 3x                   3x 3x               45x                                           6x   2x                 34x 63x         50x       87x 118x         1x       1x     3x 84x     45x    
import { identity } from "@benneq/function";
import { count, flatMap, map, some } from "@benneq/iterable";
import { Entry } from "@benneq/object";
import { MultiMap } from "./_types";
 
/**
 * A {@link AbstractMultiMap} can have multiple values per key.
 *
 * @typeParam K - the key type
 * @typeParam V - the value type
 */
export abstract class AbstractMultiMap<K, V> implements MultiMap<K, V> {
  #value;
 
  /**
   * Create a new {@link AbstractMultiMap} from the given {@link Map}.
   *
   * @param map - the underlying {@link Map} object to use
   */
  protected constructor(map: Map<K, Iterable<V>>) {
    this.#value = map;
  }
 
  clear(): void {
    this.#value.clear();
  }
 
  abstract delete(key: K): boolean;
 
  abstract delete(key: K, value: V): boolean;
 
  forEach(callbackfn: (value: V, key: K, multiMap: this) => void): void {
    for (const [key, value] of this) {
      callbackfn(value, key, this);
    }
  }
 
  get(key: K): Iterable<V> {
    return this.#value.get(key) || [];
  }
 
  has(key: K, value?: V): boolean {
    return (
      this.#value.has(key) &&
      (!value || some((e) => e === value)(this.#value.get(key) as Iterable<V>))
    );
  }
 
  abstract set(key: K, values: Iterable<V>): this;
 
  abstract add(key: K, value: V): this;
 
  addAll(entries: Iterable<Entry<K, V>>): void {
    for (const [key, value] of entries) {
      this.add(key, value);
    }
  }
 
  get size(): number {
    return count(this) || 0;
  }
 
  entries(): IterableIterator<[K, V]> {
    return flatMap<[K, Iterable<V>], [K, V]>(([key, values]) =>
      map<V, [K, V]>((value) => [key, value])(values)
    )(this.#value);
  }
 
  keys(): IterableIterator<K> {
    return this.#value.keys();
  }
 
  values(): IterableIterator<V> {
    return flatMap<Iterable<V>, V>(identity)(this.#value.values());
  }
 
  [Symbol.iterator](): IterableIterator<[K, V]> {
    return this.entries();
  }
 
  [Symbol.toStringTag] = "MultiMap";
}