Skip to content

Commit

Permalink
Updated names again.
Browse files Browse the repository at this point in the history
  • Loading branch information
kraenhansen committed Nov 3, 2022
1 parent c170d2b commit 0a5ccf8
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 34 deletions.
18 changes: 9 additions & 9 deletions packages/realm/src/IndirectWeakCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
//
////////////////////////////////////////////////////////////////////////////

import { HashFunction, IndirectWeakMap } from "./internal";
import { IdGetter, IndirectWeakMap } from "./internal";

/**
* A cache of objects (the value) which can either be constructed on demand or retrieved from cache.
Expand All @@ -25,23 +25,23 @@ import { HashFunction, IndirectWeakMap } from "./internal";
* @internal
*/
export class IndirectWeakCache<
KeyType extends object,
ValueType extends object,
K extends object,
V extends object,
Args extends unknown[],
HashType = unknown,
> extends IndirectWeakMap<KeyType, ValueType, HashType> {
constructor(private construct: { new (...args: Args): ValueType }, hasher: HashFunction<KeyType, HashType>) {
super(hasher);
Id = unknown,
> extends IndirectWeakMap<K, V, Id> {
constructor(private construct: { new (...args: Args): V }, getId: IdGetter<K, Id>) {
super(getId);
}
/**
* Get an existing value from the cache or construct and store one in case of a miss.
* @param key Object passed to the hasher provided at construction of the cache.
* @param key Object passed to the getId function provided at construction of the cache.
* @param args An optional array of constructor arguments can be passed as well, which will be used in case of a cache miss
* to construct and store a new value object.
* @returns An existing or new value.
* @throws If `args` are not supplied and no object existed in the cache.
*/
getOrCreate(key: KeyType, args?: Args) {
getOrCreate(key: K, args?: Args) {
const existing = this.get(key);
if (existing) {
return existing;
Expand Down
48 changes: 23 additions & 25 deletions packages/realm/src/IndirectWeakMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,60 +17,58 @@
////////////////////////////////////////////////////////////////////////////

/** @internal */
export type HashFunction<KeyType, HashType> = (key: KeyType) => HashType;
export type IdGetter<K, Id> = (key: K) => Id;

/**
* A map from some type of object (the key) into another type of object (the value), where a
* function (the hasher supplied at construction) is called to derive a hash of the key,
* function (the `getId` function supplied at construction) is called to derive an id of the key,
* which is used when looking up the value. This makes it possible for multiple different key
* objects to get the same value object.
* objects to get the same value object. This is subtly different from a traditional hash map,
* the id is the only value used as basis for key equality, meaning two different key objects could
* map to the same value, as long as they derive to the same id.
* This property is what is considered "indirect" about the map.
* The map is considered weak in the sense that values are wrapped in a `WeakRef` before being
* inserted in the underling map. A value is also registered with a finalization registry, ensuring
* that their entry in the underlying map is removed when they get garbage collected,
* in an effort to make the entire `IndirectWeakMap` avoid leaks.
* @internal
*/
export class IndirectWeakMap<KeyType extends object, ValueType extends object, HashType>
implements WeakMap<KeyType, ValueType>
{
export class IndirectWeakMap<K extends object, V extends object, Id> implements WeakMap<K, V> {
[Symbol.toStringTag] = "IndirectWeakMap";

private registry = new FinalizationRegistry<HashType>((hash) => {
private registry = new FinalizationRegistry<Id>((hash) => {
this.values.delete(hash);
});

constructor(
private hasher: HashFunction<KeyType, HashType>,
private values: Map<HashType, WeakRef<ValueType>> = new Map(),
) {}
constructor(private getId: IdGetter<K, Id>, private values: Map<Id, WeakRef<V>> = new Map()) {}

set(key: KeyType, value: ValueType): this {
const hash = this.hasher(key);
set(key: K, value: V): this {
const id = this.getId(key);
const ref = new WeakRef(value);
// Unregister the finalization registry on value being removed from the map
// to avoid its finalization to prune the new value from the map of values.
const existingRef = this.values.get(hash);
const existingRef = this.values.get(id);
if (existingRef) {
this.registry.unregister(existingRef);
}
// Register the new value with the finalization registry, to prune its WeakRef from
// the map of values.
this.registry.register(value, hash, ref);
this.values.set(hash, ref);
// Register the new value with the finalization registry,
// to prune its WeakRef from the map of values.
this.registry.register(value, id, ref);
this.values.set(id, ref);
return this;
}

has(key: KeyType): boolean {
has(key: K): boolean {
return this.get(key) !== undefined;
}

get(key: KeyType): ValueType | undefined {
const hash = this.hasher(key);
return this.values.get(hash)?.deref();
get(key: K): V | undefined {
const id = this.getId(key);
return this.values.get(id)?.deref();
}

delete(key: KeyType): boolean {
const hash = this.hasher(key);
return this.values.delete(hash);
delete(key: K): boolean {
const id = this.getId(key);
return this.values.delete(id);
}
}

0 comments on commit 0a5ccf8

Please sign in to comment.