Spaces:
Sleeping
Sleeping
; | |
var GetIntrinsic = require('get-intrinsic'); | |
var callBound = require('call-bind/callBound'); | |
var inspect = require('object-inspect'); | |
var $TypeError = GetIntrinsic('%TypeError%'); | |
var $WeakMap = GetIntrinsic('%WeakMap%', true); | |
var $Map = GetIntrinsic('%Map%', true); | |
var $weakMapGet = callBound('WeakMap.prototype.get', true); | |
var $weakMapSet = callBound('WeakMap.prototype.set', true); | |
var $weakMapHas = callBound('WeakMap.prototype.has', true); | |
var $mapGet = callBound('Map.prototype.get', true); | |
var $mapSet = callBound('Map.prototype.set', true); | |
var $mapHas = callBound('Map.prototype.has', true); | |
/* | |
* This function traverses the list returning the node corresponding to the | |
* given key. | |
* | |
* That node is also moved to the head of the list, so that if it's accessed | |
* again we don't need to traverse the whole list. By doing so, all the recently | |
* used nodes can be accessed relatively quickly. | |
*/ | |
var listGetNode = function (list, key) { // eslint-disable-line consistent-return | |
for (var prev = list, curr; (curr = prev.next) !== null; prev = curr) { | |
if (curr.key === key) { | |
prev.next = curr.next; | |
curr.next = list.next; | |
list.next = curr; // eslint-disable-line no-param-reassign | |
return curr; | |
} | |
} | |
}; | |
var listGet = function (objects, key) { | |
var node = listGetNode(objects, key); | |
return node && node.value; | |
}; | |
var listSet = function (objects, key, value) { | |
var node = listGetNode(objects, key); | |
if (node) { | |
node.value = value; | |
} else { | |
// Prepend the new node to the beginning of the list | |
objects.next = { // eslint-disable-line no-param-reassign | |
key: key, | |
next: objects.next, | |
value: value | |
}; | |
} | |
}; | |
var listHas = function (objects, key) { | |
return !!listGetNode(objects, key); | |
}; | |
module.exports = function getSideChannel() { | |
var $wm; | |
var $m; | |
var $o; | |
var channel = { | |
assert: function (key) { | |
if (!channel.has(key)) { | |
throw new $TypeError('Side channel does not contain ' + inspect(key)); | |
} | |
}, | |
get: function (key) { // eslint-disable-line consistent-return | |
if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { | |
if ($wm) { | |
return $weakMapGet($wm, key); | |
} | |
} else if ($Map) { | |
if ($m) { | |
return $mapGet($m, key); | |
} | |
} else { | |
if ($o) { // eslint-disable-line no-lonely-if | |
return listGet($o, key); | |
} | |
} | |
}, | |
has: function (key) { | |
if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { | |
if ($wm) { | |
return $weakMapHas($wm, key); | |
} | |
} else if ($Map) { | |
if ($m) { | |
return $mapHas($m, key); | |
} | |
} else { | |
if ($o) { // eslint-disable-line no-lonely-if | |
return listHas($o, key); | |
} | |
} | |
return false; | |
}, | |
set: function (key, value) { | |
if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { | |
if (!$wm) { | |
$wm = new $WeakMap(); | |
} | |
$weakMapSet($wm, key, value); | |
} else if ($Map) { | |
if (!$m) { | |
$m = new $Map(); | |
} | |
$mapSet($m, key, value); | |
} else { | |
if (!$o) { | |
/* | |
* Initialize the linked list as an empty node, so that we don't have | |
* to special-case handling of the first node: we can always refer to | |
* it as (previous node).next, instead of something like (list).head | |
*/ | |
$o = { key: {}, next: null }; | |
} | |
listSet($o, key, value); | |
} | |
} | |
}; | |
return channel; | |
}; | |