qnce-engine
Version:
Core QNCE (Quantum Narrative Convergence Engine) - Framework agnostic narrative engine with performance optimization
297 lines • 7.71 kB
JavaScript
"use strict";
// S2-T1: Object Pooling for Narrative Objects
// Generic object pool to eliminate runtime allocations and reduce GC pressure
Object.defineProperty(exports, "__esModule", { value: true });
exports.poolManager = exports.PoolManager = exports.PooledAsset = exports.PooledNode = exports.PooledFlow = exports.ObjectPool = void 0;
/**
* Generic Object Pool for QNCE narrative objects
* Reduces GC pressure by reusing objects instead of creating new ones
*/
class ObjectPool {
pool = [];
createFn;
maxSize;
created = 0;
borrowed = 0;
returned = 0;
constructor(createFn, initialSize = 10, maxSize = 100) {
this.createFn = createFn;
this.maxSize = maxSize;
// Pre-populate pool
for (let i = 0; i < initialSize; i++) {
const obj = this.createFn();
obj.setInUse(false);
this.pool.push(obj);
this.created++;
}
}
/**
* Borrow an object from the pool
*/
borrow() {
let obj;
if (this.pool.length > 0) {
obj = this.pool.pop();
}
else {
// Pool exhausted, create new object
obj = this.createFn();
this.created++;
}
obj.reset();
obj.setInUse(true);
this.borrowed++;
return obj;
}
/**
* Return an object to the pool
*/
return(obj) {
if (!obj.isInUse()) {
console.warn('Attempting to return object that is not in use');
return;
}
obj.setInUse(false);
this.returned++;
// Only return to pool if under max size
if (this.pool.length < this.maxSize) {
this.pool.push(obj);
}
// Otherwise let GC handle it (controlled disposal)
}
/**
* Get pool statistics for monitoring
*/
getStats() {
return {
poolSize: this.pool.length,
maxSize: this.maxSize,
created: this.created,
borrowed: this.borrowed,
returned: this.returned,
inUse: this.borrowed - this.returned,
hitRate: this.borrowed > 0 ? ((this.borrowed - this.created) / this.borrowed) * 100 : 0
};
}
/**
* Clear the pool (useful for testing)
*/
clear() {
this.pool.forEach(obj => obj.setInUse(false));
this.pool.length = 0;
this.created = 0;
this.borrowed = 0;
this.returned = 0;
}
/**
* Resize the pool
*/
resize(newSize) {
if (newSize < this.pool.length) {
// Shrink pool
this.pool.splice(newSize);
}
else if (newSize > this.pool.length) {
// Grow pool
const toAdd = newSize - this.pool.length;
for (let i = 0; i < toAdd && this.pool.length < this.maxSize; i++) {
const obj = this.createFn();
obj.setInUse(false);
this.pool.push(obj);
this.created++;
}
}
}
}
exports.ObjectPool = ObjectPool;
/**
* Pooled Flow object for narrative state management
*/
class PooledFlow {
_inUse = false;
nodeId = '';
timestamp = 0;
metadata = {};
transitions = [];
constructor() {
this.reset();
}
reset() {
this.nodeId = '';
this.timestamp = 0;
this.metadata = {};
this.transitions.length = 0;
}
isInUse() {
return this._inUse;
}
setInUse(inUse) {
this._inUse = inUse;
}
// Flow-specific methods
initialize(nodeId, metadata) {
this.nodeId = nodeId;
this.timestamp = performance.now();
if (metadata) {
this.metadata = { ...metadata };
}
}
addTransition(fromNodeId, toNodeId) {
this.transitions.push(`${fromNodeId}->${toNodeId}`);
}
getDuration() {
return performance.now() - this.timestamp;
}
}
exports.PooledFlow = PooledFlow;
/**
* Pooled Node object for narrative content
*/
class PooledNode {
_inUse = false;
id = '';
text = '';
choices = [];
flags = {};
lastAccessed = 0;
constructor() {
this.reset();
}
reset() {
this.id = '';
this.text = '';
this.choices.length = 0;
this.flags = {};
this.lastAccessed = 0;
}
isInUse() {
return this._inUse;
}
setInUse(inUse) {
this._inUse = inUse;
}
// Node-specific methods
initialize(id, text, choices = []) {
this.id = id;
this.text = text;
this.choices = [...choices];
this.lastAccessed = performance.now();
}
touch() {
this.lastAccessed = performance.now();
}
}
exports.PooledNode = PooledNode;
/**
* Pooled Asset object for narrative resources
*/
class PooledAsset {
_inUse = false;
id = '';
type = '';
data = null;
size = 0;
loaded = false;
constructor() {
this.reset();
}
reset() {
this.id = '';
this.type = '';
this.data = null;
this.size = 0;
this.loaded = false;
}
isInUse() {
return this._inUse;
}
setInUse(inUse) {
this._inUse = inUse;
}
// Asset-specific methods
initialize(id, type, data) {
this.id = id;
this.type = type;
this.data = data;
this.size = this.calculateSize(data);
this.loaded = true;
}
calculateSize(data) {
if (typeof data === 'string') {
return data.length * 2; // Approximate UTF-16 size
}
if (data && typeof data === 'object') {
return JSON.stringify(data).length * 2;
}
return 0;
}
}
exports.PooledAsset = PooledAsset;
/**
* Pool Manager - Centralized management of all object pools
*/
class PoolManager {
static instance;
flowPool;
nodePool;
assetPool;
constructor() {
// Initialize pools with different sizes based on expected usage
this.flowPool = new ObjectPool(() => new PooledFlow(), 5, 50);
this.nodePool = new ObjectPool(() => new PooledNode(), 20, 200);
this.assetPool = new ObjectPool(() => new PooledAsset(), 10, 100);
}
static getInstance() {
if (!PoolManager.instance) {
PoolManager.instance = new PoolManager();
}
return PoolManager.instance;
}
// Flow pool methods
borrowFlow() {
return this.flowPool.borrow();
}
returnFlow(flow) {
this.flowPool.return(flow);
}
// Node pool methods
borrowNode() {
return this.nodePool.borrow();
}
returnNode(node) {
this.nodePool.return(node);
}
// Asset pool methods
borrowAsset() {
return this.assetPool.borrow();
}
returnAsset(asset) {
this.assetPool.return(asset);
}
// Statistics and monitoring
getAllStats() {
return {
flows: this.flowPool.getStats(),
nodes: this.nodePool.getStats(),
assets: this.assetPool.getStats()
};
}
// Performance monitoring
getGCPressureReduction() {
const stats = this.getAllStats();
const totalHitRate = (stats.flows.hitRate +
stats.nodes.hitRate +
stats.assets.hitRate) / 3;
return totalHitRate;
}
// Cleanup for testing
clearAllPools() {
this.flowPool.clear();
this.nodePool.clear();
this.assetPool.clear();
}
}
exports.PoolManager = PoolManager;
// Export singleton instance
exports.poolManager = PoolManager.getInstance();
//# sourceMappingURL=ObjectPool.js.map