optimize(newSnapshot, capturedFiles) {
		/**
		 * @param {SnapshotOptimizationEntry} entry optimization entry
		 * @returns {void}
		 */
		const increaseSharedAndStoreOptimizationEntry = entry => {
			if (entry.children !== undefined) {
				for (const child of entry.children) {
					increaseSharedAndStoreOptimizationEntry(child);
				}
			}
			entry.shared++;
			storeOptimizationEntry(entry);
		};
		/**
		 * @param {SnapshotOptimizationEntry} entry optimization entry
		 * @returns {void}
		 */
		const storeOptimizationEntry = entry => {
			for (const path of /** @type {SnapshotContent} */ (
				entry.snapshotContent
			)) {
				const old =
					/** @type {SnapshotOptimizationEntry} */
					(this._map.get(path));
				if (old.shared < entry.shared) {
					this._map.set(path, entry);
				}
				capturedFiles.delete(path);
			}
		};

		/** @type {SnapshotOptimizationEntry | undefined} */
		let newOptimizationEntry;

		const capturedFilesSize = capturedFiles.size;

		/** @type {Set<SnapshotOptimizationEntry> | undefined} */
		const optimizationEntries = new Set();

		for (const path of capturedFiles) {
			const optimizationEntry = this._map.get(path);
			if (optimizationEntry === undefined) {
				if (newOptimizationEntry === undefined) {
					newOptimizationEntry = {
						snapshot: newSnapshot,
						shared: 0,
						snapshotContent: undefined,
						children: undefined
					};
				}
				this._map.set(path, newOptimizationEntry);
			} else {
				optimizationEntries.add(optimizationEntry);
			}
		}

		optimizationEntriesLabel: for (const optimizationEntry of optimizationEntries) {
			const snapshot = optimizationEntry.snapshot;
			if (optimizationEntry.shared > 0) {
				// It's a shared snapshot
				// We can't change it, so we can only use it when all files match
				// and startTime is compatible
				if (
					this._useStartTime &&
					newSnapshot.startTime &&
					(!snapshot.startTime || snapshot.startTime > newSnapshot.startTime)
				) {
					continue;
				}
				const nonSharedFiles = new Set();
				const snapshotContent =
					/** @type {NonNullable<SnapshotOptimizationEntry["snapshotContent"]>} */
					(optimizationEntry.snapshotContent);
				const snapshotEntries =
					/** @type {SnapshotOptimizationValue<U, T>} */
					(this._get(snapshot));
				for (const path of snapshotContent) {
					if (!capturedFiles.has(path)) {
						if (!snapshotEntries.has(path)) {
							// File is not shared and can't be removed from the snapshot
							// because it's in a child of the snapshot
							continue optimizationEntriesLabel;
						}
						nonSharedFiles.add(path);
					}
				}
				if (nonSharedFiles.size === 0) {
					// The complete snapshot is shared
					// add it as child
					newSnapshot.addChild(snapshot);
					increaseSharedAndStoreOptimizationEntry(optimizationEntry);
					this._statReusedSharedSnapshots++;
				} else {
					// Only a part of the snapshot is shared
					const sharedCount = snapshotContent.size - nonSharedFiles.size;
					if (sharedCount < MIN_COMMON_SNAPSHOT_SIZE) {
						// Common part it too small
						continue;
					}
					// Extract common timestamps from both snapshots
					let commonMap;
					if (this._isSet) {
						commonMap = new Set();
						for (const path of /** @type {Set<string>} */ (snapshotEntries)) {
							if (nonSharedFiles.has(path)) continue;
							commonMap.add(path);
							snapshotEntries.delete(path);
						}
					} else {
						commonMap = new Map();
						const map = /** @type {Map<string, T>} */ (snapshotEntries);
						for (const [path, value] of map) {
							if (nonSharedFiles.has(path)) continue;
							commonMap.set(path, value);
							snapshotEntries.delete(path);
						}
					}
					// Create and attach snapshot
					const commonSnapshot = new Snapshot();
					if (this._useStartTime) {
						commonSnapshot.setMergedStartTime(newSnapshot.startTime, snapshot);
					}
					this._set(
						commonSnapshot,
						/** @type {SnapshotOptimizationValue<U, T>} */ (commonMap)
					);
					newSnapshot.addChild(commonSnapshot);
					snapshot.addChild(commonSnapshot);
					// Create optimization entry
					const newEntry = {
						snapshot: commonSnapshot,
						shared: optimizationEntry.shared + 1,
						snapshotContent: new Set(commonMap.keys()),
						children: undefined
					};
					if (optimizationEntry.children === undefined)
						optimizationEntry.children = new Set();
					optimizationEntry.children.add(newEntry);
					storeOptimizationEntry(newEntry);
					this._statSharedSnapshots++;
				}
			} else {
				// It's a unshared snapshot
				// We can extract a common shared snapshot
				// with all common files
				const snapshotEntries = this._get(snapshot);
				if (snapshotEntries === undefined) {
					// Incomplete snapshot, that can't be used
					continue;
				}
				let commonMap;
				if (this._isSet) {
					commonMap = new Set();
					const set = /** @type {Set<string>} */ (snapshotEntries);
					if (capturedFiles.size < set.size) {
						for (const path of capturedFiles) {
							if (set.has(path)) commonMap.add(path);
						}
					} else {
						for (const path of set) {
							if (capturedFiles.has(path)) commonMap.add(path);
						}
					}
				} else {
					commonMap = new Map();
					const map = /** @type {Map<string, T>} */ (snapshotEntries);
					for (const path of capturedFiles) {
						const ts = map.get(path);
						if (ts === undefined) continue;
						commonMap.set(path, ts);
					}
				}

				if (commonMap.size < MIN_COMMON_SNAPSHOT_SIZE) {
					// Common part it too small
					continue;
				}
				// Create and attach snapshot
				const commonSnapshot = new Snapshot();
				if (this._useStartTime) {
					commonSnapshot.setMergedStartTime(newSnapshot.startTime, snapshot);
				}
				this._set(
					commonSnapshot,
					/** @type {SnapshotOptimizationValue<U, T>} */
					(commonMap)
				);
				newSnapshot.addChild(commonSnapshot);
				snapshot.addChild(commonSnapshot);
				// Remove files from snapshot
				for (const path of commonMap.keys()) snapshotEntries.delete(path);
				const sharedCount = commonMap.size;
				this._statItemsUnshared -= sharedCount;
				this._statItemsShared += sharedCount;
				// Create optimization entry
				storeOptimizationEntry({
					snapshot: commonSnapshot,
					shared: 2,
					snapshotContent: new Set(commonMap.keys()),
					children: undefined
				});
				this._statSharedSnapshots++;
			}
		}
		const unshared = capturedFiles.size;
		this._statItemsUnshared += unshared;
		this._statItemsShared += capturedFilesSize - unshared;
	}
@param {Snapshot} newSnapshot snapshot
@param {Set<string>} capturedFiles files to snapshot/share
@returns {void}