Something went wrong. Try again.
A functional toolkit for authoring resource-leveling algorithms — compose constraint and scoring blocks, enumerate feasible schedules
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117import type { FixedMeta } from "./FixedMeta.ts";import { MppUtility } from "./MppUtility.ts";
export class FixedData { private readonly offsetIndex: Map<number, number>; public readonly raw: Uint8Array; private readonly records: (Uint8Array | null)[];
constructor( raw: Uint8Array, records: (Uint8Array | null)[], offsets: number[], ) { this.raw = raw; this.records = records; this.offsetIndex = new Map<number, number>(); for (let i = 0; i < offsets.length; i++) { const offset = offsets[i]!; if (!this.offsetIndex.has(offset)) { this.offsetIndex.set(offset, i); } } }
get count(): number { return this.records.length; }
getByteArrayValue(index: number): Uint8Array | null { return this.records[index] ?? null; }
getIndexFromOffset(offset: number): number { return this.offsetIndex.get(offset) ?? -1; }
static fromMeta( meta: FixedMeta, raw: Uint8Array, maxExpectedSize = 0, minSize = 0, ): FixedData { const records: (Uint8Array | null)[] = []; const offsets: number[] = [];
for (let index = 0; index < meta.adjustedItemCount; index += 1) { const metaData = meta.getByteArrayValue(index); if (!metaData) { records.push(null); offsets.push(-1); continue; }
const itemOffset = MppUtility.getInt(metaData, 4); offsets.push(itemOffset); if (itemOffset < 0 || itemOffset > raw.length) { records.push(null); continue; }
let itemSize: number; if (index + 1 === meta.adjustedItemCount) { itemSize = raw.length - itemOffset; } else { const nextMetaData = meta.getByteArrayValue(index + 1); const nextOffset = nextMetaData ? MppUtility.getInt(nextMetaData, 4) : raw.length; itemSize = nextOffset - itemOffset; }
if (itemSize === 0) { itemSize = minSize; }
const available = raw.length - itemOffset; if (itemSize < 0 || itemSize > available) { itemSize = maxExpectedSize === 0 ? available : Math.min(maxExpectedSize, available); }
if (maxExpectedSize !== 0 && itemSize > maxExpectedSize) { itemSize = maxExpectedSize; }
records.push( itemSize > 0 ? raw.subarray(itemOffset, itemOffset + itemSize) : null, ); }
return new FixedData(raw, records, offsets); }
static fromFixedSize( raw: Uint8Array, itemSize: number, readRemainderBlock = false, ): FixedData { const count = Math.floor(raw.length / itemSize) + (readRemainderBlock && raw.length % itemSize !== 0 ? 1 : 0); const records: (Uint8Array | null)[] = []; const offsets: number[] = [];
for (let index = 0; index < count; index += 1) { const start = index * itemSize; const end = Math.min(raw.length, start + itemSize); records.push(raw.subarray(start, end)); offsets.push(start); }
return new FixedData(raw, records, offsets); }}