n-way-set-associative-cache
Version:
A TypeScript implementation of an N-way set-associative cache with configurable replacement policies, supporting operations like put, get, delete, and listAll. Optimized for performance and extensibility.
265 lines (253 loc) • 7.4 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
NWaySetAssociativeCache: () => NWaySetAssociativeCache
});
module.exports = __toCommonJS(index_exports);
// src/abstract/CacheDataStorageManager.ts
var CacheDataStorageManager = class {
capacity;
evictionManager;
constructor(capacity, evictionManager) {
this.capacity = capacity;
this.evictionManager = evictionManager;
}
getCapacity() {
return this.capacity;
}
getEvictionManager() {
return this.evictionManager;
}
};
// src/storages/InMemoryStorage.ts
var InMemoryStorage = class extends CacheDataStorageManager {
storage = /* @__PURE__ */ new Map();
add(key, value) {
if (this.storage.size >= this.capacity) {
const evictionKey = this.evictionManager.selectEvictionKey();
if (evictionKey !== void 0) {
this.storage.delete(evictionKey);
}
}
this.storage.set(key, value);
this.evictionManager.recordAccess(key);
}
get(key) {
if (this.storage.has(key)) {
this.evictionManager.recordAccess(key);
}
return this.storage.get(key);
}
has(key) {
return this.storage.has(key);
}
delete(key) {
if (this.storage.delete(key)) {
this.evictionManager.removeKey(key);
return true;
}
return false;
}
listAll() {
return Array.from(this.storage.entries()).map(([key, value]) => ({ key, value }));
}
clear() {
this.storage.clear();
}
};
// src/registeries/StorageTypeRegistry.ts
var StorageRegistry = class _StorageRegistry {
static storageRegistry = /* @__PURE__ */ new Map();
static registerStorage(type, constructor) {
this.storageRegistry.set(type, constructor);
}
static getStorage(type) {
return this.storageRegistry.get(type);
}
static {
_StorageRegistry.registerStorage(
0 /* InMemoryStorage */,
InMemoryStorage
);
}
};
// src/factories/CacheDataStorageFactory.ts
var CacheDataStorageFactory = class {
create(capacity, storageType, evictionManager) {
const StorageClass = StorageRegistry.getStorage(storageType);
if (!StorageClass) {
throw new Error(`Storage type ${storageType} is not registered.`);
}
return new StorageClass(capacity, evictionManager);
}
};
// src/evictionmanagers/LruEvictionManager.ts
var LruEvictionManager = class {
order = [];
recordAccess(key) {
const index = this.order.indexOf(key);
if (index !== -1) {
this.order.splice(index, 1);
}
this.order.push(key);
}
selectEvictionKey() {
return this.order.shift();
}
removeKey(key) {
const index = this.order.indexOf(key);
if (index !== -1) {
this.order.splice(index, 1);
}
}
};
// src/evictionmanagers/MruEvictionStrategy.ts
var MruEvictionManager = class {
order = [];
recordAccess(key) {
const index = this.order.indexOf(key);
if (index !== -1) {
this.order.splice(index, 1);
}
this.order.push(key);
}
selectEvictionKey() {
return this.order.pop();
}
removeKey(key) {
const index = this.order.indexOf(key);
if (index !== -1) {
this.order.splice(index, 1);
}
}
};
// src/types/ReplacementPolicy.ts
var ReplacementPolicy = /* @__PURE__ */ ((ReplacementPolicy2) => {
ReplacementPolicy2[ReplacementPolicy2["LRU"] = 0] = "LRU";
ReplacementPolicy2[ReplacementPolicy2["MRU"] = 1] = "MRU";
return ReplacementPolicy2;
})(ReplacementPolicy || {});
// src/registeries/EvictionRegistry.ts
var EvictionManagerRegistry = class _EvictionManagerRegistry {
static registry = /* @__PURE__ */ new Map();
static register(policy, manager) {
this.registry.set(policy, manager);
}
static get(policy) {
return this.registry.get(policy);
}
static {
_EvictionManagerRegistry.register(0 /* LRU */, LruEvictionManager);
_EvictionManagerRegistry.register(1 /* MRU */, MruEvictionManager);
}
};
// src/factories/EvictionManagerFactory.ts
var EvictionManagerFactory = class {
create(policy) {
const ManagerClass = EvictionManagerRegistry.get(policy);
if (!ManagerClass) {
throw new Error(
`No eviction manager registered for policy: ${ReplacementPolicy[policy]}`
);
}
return new ManagerClass();
}
};
// src/NWaySetAssociativeCache.ts
var NWaySetAssociativeCache = class {
cache;
capacity;
ways;
policy;
storageType;
storageFactory;
evictionManagerFactory;
logger;
constructor(capacity, ways, policy = 0 /* LRU */, storageType = 0 /* InMemoryStorage */, storageFactory = new CacheDataStorageFactory(), evictionManagerFactory = new EvictionManagerFactory(), logger) {
if (capacity % ways !== 0) {
throw new Error("Capacity must be a multiple of the number of ways.");
}
this.capacity = capacity;
this.ways = ways;
this.policy = policy;
this.storageType = storageType;
this.storageFactory = storageFactory;
this.evictionManagerFactory = evictionManagerFactory;
this.cache = /* @__PURE__ */ new Map();
this.logger = logger || console;
}
getSetIndex(key) {
const numSets = Math.floor(this.capacity / this.ways);
const hashedKey = typeof key === "number" ? key : this.hashKey(key);
return Math.abs(hashedKey) % numSets;
}
hashKey(key) {
let hash = 0;
const strKey = JSON.stringify(key);
for (let i = 0; i < strKey.length; i++) {
hash = hash * 31 + strKey.charCodeAt(i) >>> 0;
}
return hash;
}
put(key, value) {
const setIndex = this.getSetIndex(key);
if (!this.cache.has(setIndex)) {
const evictionManager = this.evictionManagerFactory.create(
this.policy
);
const cacheDataStorage = this.storageFactory.create(
this.capacity,
this.storageType,
evictionManager
);
this.cache.set(setIndex, cacheDataStorage);
}
this.cache.get(setIndex).add(key, value);
}
get(key) {
const setIndex = this.getSetIndex(key);
return this.cache.get(setIndex)?.get(key);
}
has(key) {
const setIndex = this.getSetIndex(key);
return this.cache.has(setIndex) && this.cache.get(setIndex).has(key);
}
delete(key) {
const setIndex = this.getSetIndex(key);
return this.cache.get(setIndex)?.delete(key) ?? false;
}
clear() {
this.cache.clear();
}
listAll() {
const entries = [];
this.cache.forEach((storageManager) => {
storageManager.listAll().forEach((entry) => {
entries.push(entry);
});
});
return entries;
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
NWaySetAssociativeCache
});