export type PerformanceBudget = { objectCount: number; triangleCount: number; tableCells: number; maxObjectMs: number; maxTriangleMs: number; maxTableMs: number; maxHeapBytes: number }
export type PerformanceReport = { objects: { count: number; durationMs: number }; triangles: { count: number; checksum: number; durationMs: number }; table: { cells: number; checksum: number; durationMs: number }; heapBytes: number | null; pass: boolean; budget: PerformanceBudget }
const defaultBudget: PerformanceBudget = { objectCount: 1000, triangleCount: 1_000_000, tableCells: 100_000, maxObjectMs: 2_000, maxTriangleMs: 4_000, maxTableMs: 2_000, maxHeapBytes: 512 * 1024 * 1024 }
const now = () => typeof performance !== 'undefined' && typeof performance.now === 'function' ? performance.now() : Date.now()
export const runPerformanceBudget = (budget: Partial<PerformanceBudget> = {}): PerformanceReport => { const selected = { ...defaultBudget, ...budget }; for (const key of ['objectCount', 'triangleCount', 'tableCells'] as const) if (!Number.isSafeInteger(selected[key]) || selected[key] <= 0) throw new RangeError(`Performance ${key} must be a positive integer.`); const objectStart = now(); const objects = new Array(selected.objectCount); for (let index = 0; index < selected.objectCount; index += 1) objects[index] = { id: `Object${index}`, dependencies: index === 0 ? [] : [`Object${index - 1}`], value: index % 17 }; const objectDuration = now() - objectStart; const triangleStart = now(); let triangleChecksum = 0; for (let index = 0; index < selected.triangleCount; index += 1) triangleChecksum = (triangleChecksum + ((index * 31) ^ (index >>> 3))) >>> 0; const triangleDuration = now() - triangleStart; const tableStart = now(); let tableChecksum = 0; for (let index = 0; index < selected.tableCells; index += 1) tableChecksum = (tableChecksum + ((index * 13) % 997)) % 1_000_003; const tableDuration = now() - tableStart; const heapBytes = typeof performance !== 'undefined' && 'memory' in performance ? Number((performance as Performance & { memory?: { usedJSHeapSize?: number } }).memory?.usedJSHeapSize ?? 0) || null : null; return { objects: { count: objects.length, durationMs: objectDuration }, triangles: { count: selected.triangleCount, checksum: triangleChecksum, durationMs: triangleDuration }, table: { cells: selected.tableCells, checksum: tableChecksum, durationMs: tableDuration }, heapBytes, pass: objectDuration <= selected.maxObjectMs && triangleDuration <= selected.maxTriangleMs && tableDuration <= selected.maxTableMs && (heapBytes === null || heapBytes <= selected.maxHeapBytes), budget: selected } }
