-
Notifications
You must be signed in to change notification settings - Fork 0
/
reftable.js
96 lines (87 loc) · 2.6 KB
/
reftable.js
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
const debug = require('debug')(__filename.split('/').slice(-1).join())
/*
Bi-Map with support for resolving forward references
*/
class ReferenceTable {
constructor (options = {}) {
this.idFor = new Map() // obj -> id
this.objFor = new Map() // id -> obj
this.forwardRefs = new Map() // id => Set([ {item,key}, ... ])
this.seq = 0
this.genid = options.genid || (() => ('a' + this.seq++))
this.log = []
}
idForObject (value, genided) {
debug('idForObject(%O, %O)', value, genided)
let id = this.idFor.get(value)
if (!id) {
id = this.genid(value)
// value.id = id
this.idFor.set(value, id)
this.objFor.set(id, value)
if (genided) genided.add(value)
}
debug(' => %o', id)
return id
}
getObject (id) {
return this.objFor.get(id)
}
/*
sort of: item[key] = objectForId(id)
BUT it handles forward references, too, so if we don't have the
object yet, it will be set later, when we do.
*/
setValueToId (item, key, id) {
debug('setValueToId(%O, %O, %O)', item, key, id)
let value = this.objFor.get(id)
if (value) {
debug('.. set to %o', value)
item[key] = value
} else {
let frs = this.forwardRefs.get(id)
if (!frs) {
frs = new Set()
this.forwardRefs.set(id, frs)
}
frs.add({ item, key })
debug('.. forward refs = %o', frs)
}
}
gotId (id, obj) {
debug('gotId(%O, %O)', id, obj)
const oldObj = this.objFor.get(id)
if (oldObj !== undefined) {
if (oldObj !== obj) {
console.error('id %o was %o now %o', id, oldObj, obj)
throw new Error('id redefined')
}
debug('..already had it')
return
}
this.objFor.set(id, obj)
this.idFor.set(obj, id)
for (let { item, key } of this.forwardRefs.get(id) || []) {
// in case item got instantiated, we can find it
if (item._forwardTo) item = item._forwardTo
debug('..doing fwd %O[%O] = %O', item, key, obj)
item[key] = obj
debug('..did fwd %O[%O] = %O', item, key, obj)
debug('..CONFIRMING, item=%O', item)
}
debug('..done fwd')
this.forwardRefs.delete(id)
}
complete () {
debug('fdw = %O', this.forwardRefs)
for (const [id, refs] of this.forwardRefs.entries() || []) {
if (id === '(valueunknown)') continue
debug('.. %O', { id, refs })
console.error('Warning: unresolved forward refs to %O: %O', id, refs)
}
debug('reftable.idFor: %o', this.idFor)
debug('reftable.objFor: %o', this.objFor)
debug('reftable.log: %o', this.log)
}
}
module.exports = { ReferenceTable }