|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 module.metadata = { |
|
6 "stability": "experimental" |
|
7 }; |
|
8 |
|
9 "use strict"; |
|
10 |
|
11 const { Cu } = require("chrome"); |
|
12 |
|
13 function makeGetterFor(Type) { |
|
14 let cache = new WeakMap(); |
|
15 |
|
16 return function getFor(target) { |
|
17 if (!cache.has(target)) |
|
18 cache.set(target, new Type()); |
|
19 |
|
20 return cache.get(target); |
|
21 } |
|
22 } |
|
23 |
|
24 let getLookupFor = makeGetterFor(WeakMap); |
|
25 let getRefsFor = makeGetterFor(Set); |
|
26 |
|
27 function add(target, value) { |
|
28 if (has(target, value)) |
|
29 return; |
|
30 |
|
31 getLookupFor(target).set(value, true); |
|
32 getRefsFor(target).add(Cu.getWeakReference(value)); |
|
33 } |
|
34 exports.add = add; |
|
35 |
|
36 function remove(target, value) { |
|
37 getLookupFor(target).delete(value); |
|
38 } |
|
39 exports.remove = remove; |
|
40 |
|
41 function has(target, value) { |
|
42 return getLookupFor(target).has(value); |
|
43 } |
|
44 exports.has = has; |
|
45 |
|
46 function clear(target) { |
|
47 getLookupFor(target).clear(); |
|
48 getRefsFor(target).clear(); |
|
49 } |
|
50 exports.clear = clear; |
|
51 |
|
52 function iterator(target) { |
|
53 let refs = getRefsFor(target); |
|
54 |
|
55 for (let ref of refs) { |
|
56 let value = ref.get(); |
|
57 |
|
58 // If `value` is already gc'ed, it would be `null`. |
|
59 // The `has` function is using a WeakMap as lookup table, so passing `null` |
|
60 // would raise an exception because WeakMap accepts as value only non-null |
|
61 // object. |
|
62 // Plus, if `value` is already gc'ed, we do not have to take it in account |
|
63 // during the iteration, and remove it from the references. |
|
64 if (value !== null && has(target, value)) |
|
65 yield value; |
|
66 else |
|
67 refs.delete(ref); |
|
68 } |
|
69 } |
|
70 exports.iterator = iterator; |