remove unnecessary data structs Dict+MapArray

This commit is contained in:
Schluffe
2026-08-27 23:43:28 +02:00
parent 2f7957b28a
commit 7b3c9865fe
10 changed files with 12 additions and 466 deletions
+6 -7
View File
@@ -4,9 +4,8 @@ import {
entityProcessMap,
} from "#/engine/Entity.ts";
import { type Graph, getNeighbours } from "#/engine/Graph.ts";
import { box } from "#/engine/lib/box";
import { type Box, box } from "#/engine/lib/box";
import { memoize } from "#/engine/lib/cache.ts";
import MapArray from "#/engine/lib/MapArray.ts";
export type Process = (ctx: CanvasRenderingContext2D, delta: number) => void;
export type PreProcess = () => void;
@@ -24,7 +23,7 @@ export type SceneData = {
entities: Array<EntityData<unknown>>;
};
export type ComponentsMap = Map<string, MapArray<string, unknown>>;
export type ComponentsMap = Map<string, Map<string, Box<unknown>>>;
export type Scene = {
data: SceneData;
@@ -113,7 +112,7 @@ const [loadScene, sceneCache] = memoize(async (name: string) => {
const localEntityProcessMap = new Map<string, EntityProcess>();
sceneEntityProcessMap.set(name, localEntityProcessMap);
const componentsMap = new Map<string, MapArray<string, unknown>>();
const componentsMap: ComponentsMap = new Map();
sceneComponentsMap.set(name, componentsMap);
await Promise.all(
@@ -138,7 +137,7 @@ const [loadScene, sceneCache] = memoize(async (name: string) => {
if (componentsMap.has(key)) {
componentsMap.get(key)!.set(id, boxedValue);
} else {
componentsMap.set(key, new MapArray([[id, boxedValue]]));
componentsMap.set(key, new Map([[id, boxedValue]]));
}
}
},
@@ -179,6 +178,6 @@ export async function setScene(name: string): Promise<void> {
}
}
export default function <T>(name: string): MapArray<string, T> {
return currentScene.components.get(name) as MapArray<string, T>;
export default function <T>(name: string): Map<string, Box<T>> {
return currentScene.components.get(name) as Map<string, Box<T>>;
}
-64
View File
@@ -1,64 +0,0 @@
import { expect, test } from "vitest";
import {
createDictionary,
type Dictionary,
deleteEntrySave,
forEntry,
getEntry,
setEntrySave,
} from "./Dictionary.ts";
test("Dictionary", () => {
const dict: Dictionary<string, number> = createDictionary([
["a", 1],
["b", 2],
["c", 3],
]);
setEntrySave(dict, "foo", 42);
setEntrySave(dict, "bar", 0);
deleteEntrySave(dict, "bar");
expect(getEntry(dict, "foo")).toBe(42);
expect(getEntry(dict, "bar")).toBe(undefined);
expect(dict.indices.size).toBe(dict.entries.length);
let sum = 0;
forEntry(dict, (value) => {
sum += value;
});
expect(sum).toBe(48);
});
test("Dictionary don't mutate, when used 'save', while iterating", () => {
const dict: Dictionary<string, number> = createDictionary([
["a", 1],
["b", 2],
["c", 3],
]);
let sum = 0;
forEntry(dict, (value, _, index) => {
if (index < 1) {
setEntrySave(dict, "d", 4);
setEntrySave(dict, "e", 5);
}
sum += value;
});
expect(sum).toBe(6);
expect(dict.indices.size === 5).toEqual(dict.entries.length === 5);
sum = 0;
forEntry(dict, (value, _, index) => {
if (index < 1) {
deleteEntrySave(dict, "d");
deleteEntrySave(dict, "e");
}
sum += value;
});
expect(sum).toBe(15);
expect(dict.indices.size === 3).toEqual(dict.entries.length === 3);
});
-95
View File
@@ -1,95 +0,0 @@
export type Dictionary<K, V> = {
entries: Array<[K, V]>;
indices: Map<K, number>;
isIterating: boolean;
deleteQueue: Array<K>;
setQueue: Array<[K, V]>;
};
export function createDictionary<K, V>(
iterable?: Iterable<[K, V]>,
): Dictionary<K, V> {
const entries = iterable ? [...iterable] : [];
const indices = new Map(entries.map(([k], i) => [k, i]));
return {
entries,
indices,
isIterating: false,
deleteQueue: [],
setQueue: [],
};
}
export function deleteEntry<K, V>(dict: Dictionary<K, V>, key: K): void {
const index = dict.indices.get(key);
if (index === undefined) {
return;
}
const last = dict.entries.length - 1;
if (index !== last) {
dict.entries[index] = dict.entries[last];
dict.indices.set(dict.entries[index][0], index);
}
dict.entries.pop();
dict.indices.delete(key);
}
export function deleteEntrySave<K, V>(dict: Dictionary<K, V>, key: K): void {
if (dict.isIterating) {
dict.deleteQueue.push();
} else {
deleteEntry(dict, key);
}
}
export function setEntry<K, V>(
dict: Dictionary<K, V>,
[key, value]: [K, V],
): void {
const index = dict.indices.get(key);
if (index === undefined) {
dict.indices.set(key, dict.entries.length);
dict.entries.push([key, value]);
} else {
dict.entries[index][1] = value;
}
}
export function setEntrySave<K, V>(
dict: Dictionary<K, V>,
key: K,
value: V,
): void {
if (dict.isIterating) {
dict.setQueue.push([key, value]);
} else {
setEntry(dict, [key, value]);
}
}
export function getEntry<K, V>(dict: Dictionary<K, V>, key: K): V | undefined {
const index = dict.indices.get(key);
return index === undefined ? undefined : dict.entries[index][1];
}
export function forEntry<K, V>(
dict: Dictionary<K, V>,
callback: (value: V, key: K, index: number) => void,
): void {
dict.isIterating = true;
for (let i = 0; i < dict.entries.length; i++) {
callback(dict.entries[i][1], dict.entries[i][0], i);
}
dict.isIterating = false;
while (dict.deleteQueue.length > 0) {
deleteEntry(dict, dict.deleteQueue.pop()!);
}
while (dict.setQueue.length > 0) {
setEntry(dict, dict.setQueue.pop()!);
}
}
-27
View File
@@ -1,27 +0,0 @@
import { expect, test } from "vitest";
import { box } from "./box.ts";
import MapArray from "./MapArray.ts";
test("MapArray", () => {
const mapArray = new MapArray([
["a", box(1)],
["b", box(2)],
["c", box(3)],
]);
mapArray.set("foo", box(42));
mapArray.set("bar", box(0));
mapArray.delete("bar");
expect(mapArray.get("foo")!.value).toBe(42);
expect(mapArray.get("bar")).toBe(undefined);
expect(mapArray.map.size).toBe(mapArray.array.length);
expect(
mapArray.entries().reduce(
(a, c) => {
a[1].value = a[1].value + c[1].value;
return a;
},
["_", box(0)],
)[1].value,
).toBe(48);
});
-37
View File
@@ -1,37 +0,0 @@
import type { Box } from "./box.ts";
export default class MapArray<K, V> {
map: Map<K, Box<V>>;
array: Array<[K, Box<V>]>;
constructor(iterable?: Iterable<[K, Box<V>]>) {
this.map = new Map(iterable);
this.array = iterable ? [...iterable] : [];
}
delete(key: K): void {
if (this.map.delete(key)) {
this.array[this.array.findIndex((e) => e[0] === key)] =
this.array[this.array.length - 1];
this.array.pop();
}
}
set(key: K, value: Box<V>): void {
if (this.map.has(key)) {
this.array.find((e) => e[0] === key)![1] = value;
} else {
this.array.push([key, value]);
}
this.map.set(key, value);
}
get(key: K): Box<V> | undefined {
return this.map.get(key);
}
entries(): Array<[K, Box<V>]> {
return this.array;
}
}
+2 -2
View File
@@ -13,13 +13,13 @@ sceneChangeSet.add((sceneData) => {
drawables.length = 0;
const sprites = [
...sceneComponentsMap.get(sceneData.name)!.get("sprite")!.map.values(),
...sceneComponentsMap.get(sceneData.name)!.get("sprite")!.values(),
] as Array<Box<Sprite>>;
sceneComponentsMap
.get(sceneData.name)!
.get("position")!
.map.values()
.values()
.forEach((box, index) => {
drawables.push({
position: box as Box<Vector>,