UNPKG

@giro3d/giro3d

Version:

A JS/WebGL framework for 3D geospatial data visualization

90 lines (77 loc) 2.4 kB
/* * Copyright (c) 2015-2018, IGN France. * Copyright (c) 2018-2026, Giro3D team. * SPDX-License-Identifier: MIT */ import type Disposable from './Disposable'; interface RefCount { count: number; } /** * Represents an object that can be shared among multiple instances (multiple ownership). */ export default class Shared<T extends object, Owner = unknown> implements Disposable { private _disposed = false; private constructor( private readonly _object: T, private readonly _owner: Owner, private readonly _refCount: RefCount, private readonly _onDispose: (obj: T) => void, ) {} /** * The underlying shared object. */ public get object(): T { this.checkDisposed(); return this._object; } /** * Gets the original (first) owner of the shared object. */ public get owner(): Owner { this.checkDisposed(); return this._owner; } /** * Creates a new shared object with the specified owner. * @param obj - The object to share. * @param owner - The owner of the object. * @param onDispose - The callback to apply when the ref count reaches zero. */ public static new<T extends object, Owner = unknown>( obj: T, owner: Owner, onDispose: (obj: T) => void, ): Shared<T, Owner> { const result = new Shared(obj, owner, { count: 1 }, onDispose); return result; } /** * Clones the reference to the shared object, incrementing the ref count. * Note: this does _not_ clone the shared object itself. */ public clone(): Shared<T, Owner> { this.checkDisposed(); this._refCount.count++; return new Shared(this._object, this.owner, this._refCount, this._onDispose); } private checkDisposed(): void { if (this._refCount.count === 0) { throw new Error('cannot use disposed Shared object'); } } /** * Decrement the ref count of this object. If the count becomes zero, the underlying object is also disposed. */ public dispose(): void { // Idempotence of dispose() if (this._disposed) { return; } this._refCount.count--; if (this._refCount.count === 0) { this._disposed = true; this._onDispose(this._object); } } }