import type { BiMultiMapBase, ContextTypesImpl, } from '@rimbu/bimultimap/custom'; import { EmptyBase, NonEmptyBase, type WithKeyValue, } from '@rimbu/collection-types/map-custom'; import type { RelatedTo, ToJSON, TraverseState } from '@rimbu/common'; import { Stream, type StreamSource } from '@rimbu/stream'; export class BiMultiMapEmpty extends EmptyBase implements BiMultiMapBase { _NonEmptyType!: WithKeyValue['nonEmpty']; constructor(readonly context: WithKeyValue['context']) { super(); } get keyValueMultiMap(): WithKeyValue['keyValueMultiMap'] { return this.context.keyValueMultiMapContext.empty(); } get valueKeyMultiMap(): WithKeyValue['valueKeyMultiMap'] { return this.context.valueKeyMultiMapContext.empty(); } get keySize(): 0 { return 0; } streamKeys(): Stream { return Stream.empty(); } streamValues(): Stream { return Stream.empty(); } hasKey(): false { return false; } hasValue(): false { return false; } hasEntry(): false { return false; } add(key: K, value: V): WithKeyValue['nonEmpty'] { return this.context.createNonEmpty( this.context.keyValueMultiMapContext.of([key, value]), this.context.valueKeyMultiMapContext.of([value, key]) ) as WithKeyValue['nonEmpty']; } addEntries( entries: StreamSource ): WithKeyValue['nonEmpty'] { return this.context.from(entries) as WithKeyValue['nonEmpty']; } setValues( key: K, values: StreamSource ): WithKeyValue['nonEmpty'] { return this.context.from( Stream.from(values).map((value) => [key, value]) ) as WithKeyValue['nonEmpty']; } setKeys(value: V, keys: StreamSource): WithKeyValue['nonEmpty'] { return this.context.from( Stream.from(keys).map((key) => [key, value]) ) as WithKeyValue['nonEmpty']; } getValues(): WithKeyValue['keyMultiMapValues'] { return this.context.keyValueMultiMapContext.keyMapValuesContext.empty(); } getKeys(): WithKeyValue['valueMultiMapValues'] { return this.context.valueKeyMultiMapContext.keyMapValuesContext.empty(); } removeKey(): WithKeyValue['normal'] { return this as WithKeyValue['normal']; } removeKeys(): WithKeyValue['normal'] { return this as WithKeyValue['normal']; } removeEntry(): WithKeyValue['normal'] { return this as WithKeyValue['normal']; } removeEntries(): WithKeyValue['normal'] { return this as WithKeyValue['normal']; } removeValue(): WithKeyValue['normal'] { return this as WithKeyValue['normal']; } removeValues(): WithKeyValue['normal'] { return this as WithKeyValue['normal']; } toString(): string { return `${this.context.typeTag}()`; } toJSON(): ToJSON { return { dataType: this.context.typeTag, value: [], }; } toBuilder(): WithKeyValue['builder'] { return this.context.builder(); } } export class BiMultiMapNonEmpty< K, V, Tp extends ContextTypesImpl, TpG extends WithKeyValue = WithKeyValue, > extends NonEmptyBase<[K, V]> implements BiMultiMapBase.NonEmpty { _NonEmptyType!: TpG['nonEmpty']; constructor( readonly context: WithKeyValue['context'], readonly keyValueMultiMap: TpG['keyValueMultiMapNonEmpty'], readonly valueKeyMultiMap: TpG['valueKeyMultiMapNonEmpty'] ) { super(); } assumeNonEmpty(): any { return this; } asNormal(): any { return this; } get keySize(): number { return this.keyValueMultiMap.keySize; } get size(): number { return this.keyValueMultiMap.size; } stream(): Stream.NonEmpty<[K, V]> { return this.keyValueMultiMap.stream(); } streamKeys(): Stream.NonEmpty { return this.keyValueMultiMap.streamKeys(); } streamValues(): Stream.NonEmpty { return this.valueKeyMultiMap.streamKeys(); } hasKey(key: RelatedTo): boolean { return this.keyValueMultiMap.hasKey(key); } hasValue(key: RelatedTo): boolean { return this.valueKeyMultiMap.hasKey(key); } hasEntry( key: RelatedTo, value: RelatedTo ): boolean { return this.hasKey(key) && this.hasValue(value); } add(key: K, value: V): WithKeyValue['nonEmpty'] { const newKeyValueMultiMap = this.keyValueMultiMap.add(key, value); if (newKeyValueMultiMap === this.keyValueMultiMap) return this as any; const newValueKeyMultiMap = this.valueKeyMultiMap.add(value, key); return this.context.createNonEmpty( newKeyValueMultiMap, newValueKeyMultiMap ) as WithKeyValue['nonEmpty']; } addEntries( entries: StreamSource ): WithKeyValue['nonEmpty'] { const builder = this.toBuilder(); builder.addEntries(entries); return builder.build() as WithKeyValue['nonEmpty']; } setValues( key: K, values: StreamSource ): WithKeyValue['nonEmpty'] { const builder = this.toBuilder(); builder.setValues(key, values); return builder.build() as WithKeyValue['nonEmpty']; } setKeys(value: V, keys: StreamSource): WithKeyValue['nonEmpty'] { const builder = this.toBuilder(); builder.setKeys(value, keys); return builder.build() as WithKeyValue['nonEmpty']; } getValues( key: RelatedTo ): WithKeyValue['keyMultiMapValues'] { return this.keyValueMultiMap.getValues(key) as any; } getKeys( value: RelatedTo ): WithKeyValue['valueMultiMapValues'] { return this.valueKeyMultiMap.getValues(value) as any; } removeKey(key: RelatedTo): WithKeyValue['normal'] { const result = this.keyValueMultiMap.removeKeyAndGet(key); if (undefined === result) { return this as WithKeyValue['normal']; } const [newKeyValueMultiMap, oldValues] = result; if (!newKeyValueMultiMap.nonEmpty()) return this.context.empty(); const newValueKeyMultiMap = this.valueKeyMultiMap .removeEntries(oldValues.stream().map((value) => [value, key] as [V, K])) .assumeNonEmpty(); return this.context.createNonEmpty( newKeyValueMultiMap, newValueKeyMultiMap ) as WithKeyValue['normal']; } removeKeys( keys: StreamSource> ): WithKeyValue['normal'] { const builder = this.toBuilder(); builder.removeKeys(keys); return builder.build(); } removeValue( value: RelatedTo ): WithKeyValue['normal'] { const result = this.valueKeyMultiMap.removeKeyAndGet(value); if (undefined === result) { return this as WithKeyValue['normal']; } const [newValueKeyMultiMap, oldKeys] = result; if (!newValueKeyMultiMap.nonEmpty()) return this.context.empty(); const newKeyValueMultiMap = this.keyValueMultiMap .removeEntries(oldKeys.stream().map((key) => [key, value] as [K, V])) .assumeNonEmpty(); return this.context.createNonEmpty( newKeyValueMultiMap, newValueKeyMultiMap ) as WithKeyValue['normal']; } removeValues( values: StreamSource> ): WithKeyValue['normal'] { const builder = this.toBuilder(); builder.removeValues(values); return builder.build(); } removeEntry( key: RelatedTo, value: V ): WithKeyValue['normal'] { const newKeyValueMultiMap = this.keyValueMultiMap.removeEntry(key, value); if (newKeyValueMultiMap === this.keyValueMultiMap) return this as WithKeyValue['normal']; if (!newKeyValueMultiMap.nonEmpty()) return this.context.empty(); const newValueKeyMultiMap = this.valueKeyMultiMap .removeEntry(value, key as any) .assumeNonEmpty(); return this.context.createNonEmpty( newKeyValueMultiMap, newValueKeyMultiMap ) as WithKeyValue['normal']; } removeEntries( entries: StreamSource<[RelatedTo, V]> ): WithKeyValue['normal'] { const builder = this.toBuilder(); builder.removeEntries(entries); return builder.build(); } forEach( f: (entry: [K, V], index: number, halt: () => void) => void, options: { state?: TraverseState } = {} ): void { this.keyValueMultiMap.forEach(f, options); } filter( pred: (entry: [K, V], index: number, halt: () => void) => boolean, options: { negate?: boolean } = {} ): WithKeyValue['normal'] { const builder = this.context.builder(); builder.addEntries(this.stream().filter(pred, options)); if (builder.size === this.size) return this as any; return builder.build() as WithKeyValue['normal']; } toArray(): [K, V][] { return this.keyValueMultiMap.toArray(); } toString(): string { return this.keyValueMultiMap.streamKeys().join({ start: `${this.context.typeTag}(`, sep: ', ', end: ')', valueToString: (key: K) => { return `${key} <-> ${this.keyValueMultiMap .getValues(key) .stream() .join({ start: '(', sep: ', ', end: ')' })}`; }, }); } toJSON(): ToJSON<[K, V[]][], this['context']['typeTag']> { return { dataType: this.context.typeTag, value: this.keyValueMultiMap.toJSON().value, }; } toBuilder(): WithKeyValue['builder'] { return this.context.createBuilder(this as any) as WithKeyValue< Tp, K, V >['builder']; } }