From 3ea728bf62e3bf876c84ee488414763d9a883218 Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Fri, 9 Nov 2018 01:20:24 +0100
Subject: [PATCH] mol-state: optimized state tree serialization

---
 src/mol-state/immutable-tree.ts | 52 ++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 21 deletions(-)

diff --git a/src/mol-state/immutable-tree.ts b/src/mol-state/immutable-tree.ts
index 3d94a90d5..21c9a1689 100644
--- a/src/mol-state/immutable-tree.ts
+++ b/src/mol-state/immutable-tree.ts
@@ -107,48 +107,58 @@ export namespace ImmutableTree {
 
 
     function _visitChildToJson(this: Ref[], ref: Ref) { this.push(ref); }
-    interface ToJsonCtx { nodes: Ref[], parent: any, children: any, values: any, valueToJSON: (v: any) => any }
+    interface ToJsonCtx { nodes: [any, any, any[]][], refs: string[], valueToJSON: (v: any) => any }
     function _visitNodeToJson(this: ToJsonCtx, node: Node<any>) {
-        this.nodes.push(node.ref);
         const children: Ref[] = [];
         node.children.forEach(_visitChildToJson as any, children);
-        this.parent[node.ref] = node.parent;
-        this.children[node.ref] = children;
-        this.values[node.ref] = this.valueToJSON(node.value);
+        this.nodes.push([this.valueToJSON(node.value), node.parent, children]);
+        this.refs.push(node.ref);
     }
 
     export interface Serialized {
-        root: Ref,
-        nodes: Ref[],
-        parent: { [key: string]: string },
-        children: { [key: string]: any },
-        values: { [key: string]: any }
+        root: number, // root index
+        nodes: [any /** value */, number /** parent index */, number[] /** children indices */][]
     }
 
     export function toJSON<T>(tree: ImmutableTree<T>, valueToJSON: (v: T) => any): Serialized {
-        const ctx: ToJsonCtx = { nodes: [], parent: { }, children: {}, values: {}, valueToJSON };
+        const ctx: ToJsonCtx = { nodes: [], refs: [], valueToJSON };
+
         tree.nodes.forEach(_visitNodeToJson as any, ctx);
+
+        const map = new Map<string, number>();
+        let i = 0;
+        for (const n of ctx.refs) map.set(n, i++);
+
+        for (const n of ctx.nodes) {
+            n[1] = map.get(n[1]);
+            const children = n[2];
+            for (i = 0; i < children.length; i++) {
+                children[i] = map.get(children[i]);
+            }
+        }
         return {
-            root: tree.rootRef,
-            nodes: ctx.nodes,
-            parent: ctx.parent,
-            children: ctx.children,
-            values: ctx.values
+            root: map.get(tree.rootRef)!,
+            nodes: ctx.nodes
         };
     }
 
     export function fromJSON<T>(data: Serialized, getRef: (v: T) => Ref, valueFromJSON: (v: any) => T): ImmutableTree<T> {
         const nodes = ImmutableMap<ImmutableTree.Ref, Node<T>>().asMutable();
-        for (const ref of data.nodes) {
+
+        const values = data.nodes.map(n => valueFromJSON(n[0]));
+        let i = 0;
+        for (const value of values) {
+            const node = data.nodes[i++];
+            const ref = getRef(value);
             nodes.set(ref, {
                 ref,
-                value: valueFromJSON(data.values[ref]),
+                value,
                 version: 0,
-                parent: data.parent[ref],
-                children: OrderedSet(data.children[ref])
+                parent: getRef(values[node[1]]),
+                children: OrderedSet(node[2].map(c => getRef(values[c])))
             });
         }
-        return new Impl(data.root, nodes.asImmutable(), getRef, 0);
+        return new Impl(getRef(values[data.root]), nodes.asImmutable(), getRef, 0);
     }
 
     function checkSetRef(oldRef: ImmutableTree.Ref, newRef: ImmutableTree.Ref) {
-- 
GitLab