1// Tipi per le opzioni di configurazione
2interface MemoizeOptions {
3 maxCacheSize: number;
4 ttl: number; // Time To Live in millisecondi
5 cacheKeyGenerator?: <T extends unknown[]>(...args: T) => string;
6}
7
8// Tipo per le statistiche della cache
9interface CacheStats {
10 hits: number;
11 misses: number;
12 size: number;
13 averageAccessTime: number;
14}
15
16// Implementazione avanzata con gestione completa della cache
17function advancedMemoize<T extends AnyFunction>(
18 fn: T,
19 options: Partial<MemoizeOptions> = {},
20): MemoizedFunction<T> & { getStats: () => CacheStats } {
21 const {
22 maxCacheSize = 1000,
23 ttl = Infinity,
24 cacheKeyGenerator = JSON.stringify,
25 } = options;
26
27 const cache = new Map<string, CacheEntry<ReturnType<T>>>();
28 const stats = {
29 hits: 0,
30 misses: 0,
31 totalAccessTime: 0,
32 accessCount: 0,
33 };
34
35 const memoized = (...args: Parameters<T>): ReturnType<T> => {
36 const startTime = performance.now();
37 const key = cacheKeyGenerator(args);
38 const now = Date.now();
39 const cached = cache.get(key);
40
41 const updateStats = (hit: boolean): void => {
42 const accessTime = performance.now() - startTime;
43 stats.totalAccessTime += accessTime;
44 stats.accessCount += 1;
45 if (hit) stats.hits += 1;
46 else stats.misses += 1;
47 };
48
49 // Verifica della validità della cache
50 if (cached && now - cached.timestamp <= ttl) {
51 updateStats(true);
52 return cached.value;
53 }
54
55 // Rimozione delle voci scadute se necessario
56 if (cached) {
57 cache.delete(key);
58 }
59
60 // Gestione della dimensione della cache
61 if (cache.size >= maxCacheSize) {
62 const oldestKey = cache.keys().next().value;
63 cache.delete(oldestKey);
64 }
65
66 const result = fn(...args);
67 cache.set(key, { value: result, timestamp: now });
68 updateStats(false);
69 return result;
70 };
71
72 // Aggiunta dei metodi di utilità
73 const enhanced = memoized as MemoizedFunction<T> & {
74 getStats: () => CacheStats;
75 };
76 enhanced.clearCache = () => cache.clear();
77 enhanced.getStats = () => ({
78 hits: stats.hits,
79 misses: stats.misses,
80 size: cache.size,
81 averageAccessTime:
82 stats.accessCount > 0 ? stats.totalAccessTime / stats.accessCount : 0,
83 });
84
85 return enhanced;
86}