-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdataGraph.js
More file actions
141 lines (126 loc) · 3.27 KB
/
Copy pathdataGraph.js
File metadata and controls
141 lines (126 loc) · 3.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
class Util {
static binaryToHex(binary) {
return goshawkdb.binaryToHex(binary)
}
static arrayBufferEqual(a1, a2) {
if (a1 === null && a2 !== null) {
return true
}
if (a1 !== null && a2 === null) {
return true
}
if (a1.byteLength !== a2.byteLength) {
return false
}
const u1 = new Uint8Array(a1)
const u2 = new Uint8Array(a2)
for (let i = 0; i < u1.length; ++i) {
if (u1[i] != u2[i]) {
return false
}
}
return true
}
static removeEdge(edges, source, destination) {
if (edges.has(source)) {
edges.get(source).delete(destination)
if (edges.get(source).size === 0) {
edges.delete(source)
}
}
}
static forEachEdge(edges, fn) {
for (let [source, dests] of edges) {
for (let [dest, data] of dests) {
fn(source, dest, data)
}
}
}
static nodeEqual(node1, node2) {
if (!Util.arrayBufferEqual(node1.value, node2.value)) {
return false
}
if (node1.read !== node2.read || node1.write !== node2.write || node1.name !== node2.name) {
return false
}
return true
}
}
class DataGraph {
constructor() {
this.nodes = new Map()
this.edges = new Map()
}
getNode(ref) {
const hashable = Util.binaryToHex(ref.varId)
if (!this.nodes.has(hashable)) {
this.nodes.set(hashable, {id: hashable, write: ref.write, read: ref.read, visited: false, value: null})
} else {
const data = this.nodes.get(hashable)
data.read = data.read || ref.read
data.write = data.write || ref.write
}
return this.nodes.get(hashable)
}
addEdge(source, destination, read, write) {
if (!this.edges.has(source)) {
this.edges.set(source, new Map())
}
this.edges.get(source).set(destination, {read, write})
}
diff(previousGraph) {
// current nodes - last nodes
const addedNodes = new Set(this.nodes.keys())
previousGraph.nodes.forEach((value, key) => {
addedNodes.delete(key)
})
// last nodes - current nodes
const removedNodes = new Set(previousGraph.nodes.keys())
this.nodes.forEach((value, key) => {
removedNodes.delete(key)
})
// nodes we used to have that weren't removed that are different now
const changedValues = new Set()
for (let [lastNodeLabel, lastNode] of previousGraph.nodes) {
if (!removedNodes.has(lastNodeLabel)) {
const newNode = this.nodes.get(lastNodeLabel)
if (!Util.nodeEqual(newNode, lastNode)) {
changedValues.add(lastNodeLabel)
}
}
}
// all the new nodes - the old nodes
const addedEdges = new Map(this.edges)
Util.forEachEdge(previousGraph.edges, (source, destination, data) => {
Util.removeEdge(addedEdges, source, destination)
})
// old nodes - all the new nodes
const removedEdges = new Map(previousGraph.edges)
Util.forEachEdge(this.edges, (source, destination, data) => {
Util.removeEdge(removedEdges, source, destination)
})
return {
graph: this,
previousGraph,
addedNodes, removedNodes,
changedValues,
addedEdges, removedEdges
}
}
visit(txn, ref) {
const node = this.getNode(ref)
if (node.visited) {
return
}
if (ref.read) {
const {value, refs} = txn.read(ref)
node.value = value
node.visited = true
for (let otherRef of refs) {
const otherLabel = Util.binaryToHex(otherRef.varId)
this.addEdge(node.id, otherLabel, otherRef.read, otherRef.write)
this.visit(txn, otherRef)
}
}
}
}