You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.3 KiB
124 lines
3.3 KiB
'use strict'; |
|
|
|
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; |
|
};
|
|
|