From 88744a970ddc5c10e6722f35eb1f5c65b305dbe1 Mon Sep 17 00:00:00 2001
From: Sacha Froment <sfroment42@gmail.com>
Date: Tue, 18 Feb 2025 15:54:26 +0100
Subject: [PATCH 1/2] perf: better topo dfs perf

Signed-off-by: Sacha Froment <sfroment42@gmail.com>
---
 packages/object/src/hashgraph/index.ts    | 21 +++++++++++++--------
 packages/object/src/utils/objectSet.ts    |  5 +++++
 packages/object/tests/actiontypes.test.ts | 15 ++++++++++-----
 3 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/packages/object/src/hashgraph/index.ts b/packages/object/src/hashgraph/index.ts
index f0c3edc7b..1d0524f9f 100644
--- a/packages/object/src/hashgraph/index.ts
+++ b/packages/object/src/hashgraph/index.ts
@@ -166,16 +166,20 @@ export class HashGraph {
 
 	dfsTopologicalSortIterative(origin: Hash, subgraph: ObjectSet<Hash>): Hash[] {
 		const visited = new ObjectSet<Hash>();
-		const result: Hash[] = [];
-		const stack: Hash[] = [origin];
+		const result: Hash[] = Array(subgraph.size);
+		const stack: Hash[] = Array(subgraph.size);
 		const processing = new ObjectSet<Hash>();
+		let resultIndex = subgraph.size - 1;
+		let stackIndex = 0;
+		stack[stackIndex] = origin;
 
-		while (stack.length > 0) {
-			const node = stack[stack.length - 1];
+		while (resultIndex >= 0) {
+			const node = stack[stackIndex];
 
 			if (visited.has(node)) {
-				stack.pop();
-				result.push(node);
+				result[resultIndex] = node;
+				stackIndex--;
+				resultIndex--;
 				processing.delete(node);
 				continue;
 			}
@@ -188,13 +192,14 @@ export class HashGraph {
 				for (const neighbor of neighbors.sort()) {
 					if (processing.has(neighbor)) throw new Error("Graph contains a cycle!");
 					if (subgraph.has(neighbor) && !visited.has(neighbor)) {
-						stack.push(neighbor);
+						stackIndex++;
+						stack[stackIndex] = neighbor;
 					}
 				}
 			}
 		}
 
-		return result.reverse();
+		return result;
 	}
 
 	/* Topologically sort the vertices in the whole hashgraph or the past of a given vertex. */
diff --git a/packages/object/src/utils/objectSet.ts b/packages/object/src/utils/objectSet.ts
index cd11095b9..94fc20628 100644
--- a/packages/object/src/utils/objectSet.ts
+++ b/packages/object/src/utils/objectSet.ts
@@ -1,19 +1,24 @@
 export class ObjectSet<T extends string | number | symbol> {
 	set: { [key in T]: boolean };
+	size: number;
 
 	constructor(iterable: Iterable<T> = []) {
 		this.set = {} as { [key in T]: boolean };
+		this.size = 0;
 		for (const item of iterable) {
 			this.set[item] = true;
+			this.size++;
 		}
 	}
 
 	add(item: T): void {
 		this.set[item] = true;
+		this.size++;
 	}
 
 	delete(item: T): void {
 		delete this.set[item];
+		this.size--;
 	}
 
 	has(item: T): boolean {
diff --git a/packages/object/tests/actiontypes.test.ts b/packages/object/tests/actiontypes.test.ts
index bf798d8d7..13eee4827 100644
--- a/packages/object/tests/actiontypes.test.ts
+++ b/packages/object/tests/actiontypes.test.ts
@@ -89,23 +89,28 @@ describe("Test: ActionTypes (Nop and Swap)", () => {
 		addMul.add(5);
 		drp.merge(drp2.vertices);
 		drp2.merge(drp.vertices);
-
+		vi.setSystemTime(new Date(Date.UTC(1998, 11, 21)));
 		addMul.mul(5);
+		vi.setSystemTime(new Date(Date.UTC(1998, 11, 22)));
 		addMul.add(5);
+		vi.setSystemTime(new Date(Date.UTC(1998, 11, 23)));
 		addMul2.add(5);
 		drp.merge(drp2.vertices);
 		drp2.merge(drp.vertices);
-		expect(addMul.query_value()).toBe(75);
-		expect(addMul2.query_value()).toBe(75);
+		expect(addMul.query_value()).toBe(55);
+		expect(addMul2.query_value()).toBe(55);
 
 		addMul2.mul(2);
+		vi.setSystemTime(new Date(Date.UTC(1998, 11, 24)));
 		addMul2.add(2);
+		vi.setSystemTime(new Date(Date.UTC(1998, 11, 25)));
 		addMul.add(3);
+		vi.setSystemTime(new Date(Date.UTC(1998, 11, 26)));
 		addMul.mul(3);
 		drp.merge(drp2.vertices);
 		drp2.merge(drp.vertices);
-		expect(addMul.query_value()).toBe(480);
-		expect(addMul2.query_value()).toBe(480);
+		expect(addMul.query_value()).toBe(510);
+		expect(addMul2.query_value()).toBe(510);
 	});
 });
 

From 427f7e006a122af0318c678c31e263ed3dd22403 Mon Sep 17 00:00:00 2001
From: Jan Lewandowski <lewandowski.jan@o2.pl>
Date: Wed, 19 Feb 2025 16:26:48 +0100
Subject: [PATCH 2/2] fix: objectset and tets

---
 packages/object/src/linearize/pairSemantics.ts |  1 -
 packages/object/src/utils/objectSet.ts         |  4 ++++
 packages/object/tests/actiontypes.test.ts      | 11 ++++-------
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/packages/object/src/linearize/pairSemantics.ts b/packages/object/src/linearize/pairSemantics.ts
index 9c3d3066c..7e18f747e 100644
--- a/packages/object/src/linearize/pairSemantics.ts
+++ b/packages/object/src/linearize/pairSemantics.ts
@@ -58,6 +58,5 @@ export function linearizePairSemantics(
 			}
 		}
 	}
-
 	return result;
 }
diff --git a/packages/object/src/utils/objectSet.ts b/packages/object/src/utils/objectSet.ts
index 94fc20628..ce70bdf9e 100644
--- a/packages/object/src/utils/objectSet.ts
+++ b/packages/object/src/utils/objectSet.ts
@@ -12,11 +12,15 @@ export class ObjectSet<T extends string | number | symbol> {
 	}
 
 	add(item: T): void {
+		if (this.has(item)) return;
+
 		this.set[item] = true;
 		this.size++;
 	}
 
 	delete(item: T): void {
+		if (!this.has(item)) return;
+
 		delete this.set[item];
 		this.size--;
 	}
diff --git a/packages/object/tests/actiontypes.test.ts b/packages/object/tests/actiontypes.test.ts
index 13eee4827..939023b35 100644
--- a/packages/object/tests/actiontypes.test.ts
+++ b/packages/object/tests/actiontypes.test.ts
@@ -89,16 +89,13 @@ describe("Test: ActionTypes (Nop and Swap)", () => {
 		addMul.add(5);
 		drp.merge(drp2.vertices);
 		drp2.merge(drp.vertices);
-		vi.setSystemTime(new Date(Date.UTC(1998, 11, 21)));
 		addMul.mul(5);
-		vi.setSystemTime(new Date(Date.UTC(1998, 11, 22)));
 		addMul.add(5);
-		vi.setSystemTime(new Date(Date.UTC(1998, 11, 23)));
 		addMul2.add(5);
 		drp.merge(drp2.vertices);
 		drp2.merge(drp.vertices);
-		expect(addMul.query_value()).toBe(55);
-		expect(addMul2.query_value()).toBe(55);
+		expect(addMul.query_value()).toBe(75);
+		expect(addMul2.query_value()).toBe(75);
 
 		addMul2.mul(2);
 		vi.setSystemTime(new Date(Date.UTC(1998, 11, 24)));
@@ -109,8 +106,8 @@ describe("Test: ActionTypes (Nop and Swap)", () => {
 		addMul.mul(3);
 		drp.merge(drp2.vertices);
 		drp2.merge(drp.vertices);
-		expect(addMul.query_value()).toBe(510);
-		expect(addMul2.query_value()).toBe(510);
+		expect(addMul.query_value()).toBe(480);
+		expect(addMul2.query_value()).toBe(480);
 	});
 });