You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
2.4 KiB
JavaScript
114 lines
2.4 KiB
JavaScript
6 years ago
|
var hasOwnProperty = Object.prototype.hasOwnProperty
|
||
|
|
||
|
module.exports = PseudoMap
|
||
|
|
||
|
function PseudoMap (set) {
|
||
|
if (!(this instanceof PseudoMap)) // whyyyyyyy
|
||
|
throw new TypeError("Constructor PseudoMap requires 'new'")
|
||
|
|
||
|
this.clear()
|
||
|
|
||
|
if (set) {
|
||
|
if ((set instanceof PseudoMap) ||
|
||
|
(typeof Map === 'function' && set instanceof Map))
|
||
|
set.forEach(function (value, key) {
|
||
|
this.set(key, value)
|
||
|
}, this)
|
||
|
else if (Array.isArray(set))
|
||
|
set.forEach(function (kv) {
|
||
|
this.set(kv[0], kv[1])
|
||
|
}, this)
|
||
|
else
|
||
|
throw new TypeError('invalid argument')
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PseudoMap.prototype.forEach = function (fn, thisp) {
|
||
|
thisp = thisp || this
|
||
|
Object.keys(this._data).forEach(function (k) {
|
||
|
if (k !== 'size')
|
||
|
fn.call(thisp, this._data[k].value, this._data[k].key)
|
||
|
}, this)
|
||
|
}
|
||
|
|
||
|
PseudoMap.prototype.has = function (k) {
|
||
|
return !!find(this._data, k)
|
||
|
}
|
||
|
|
||
|
PseudoMap.prototype.get = function (k) {
|
||
|
var res = find(this._data, k)
|
||
|
return res && res.value
|
||
|
}
|
||
|
|
||
|
PseudoMap.prototype.set = function (k, v) {
|
||
|
set(this._data, k, v)
|
||
|
}
|
||
|
|
||
|
PseudoMap.prototype.delete = function (k) {
|
||
|
var res = find(this._data, k)
|
||
|
if (res) {
|
||
|
delete this._data[res._index]
|
||
|
this._data.size--
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PseudoMap.prototype.clear = function () {
|
||
|
var data = Object.create(null)
|
||
|
data.size = 0
|
||
|
|
||
|
Object.defineProperty(this, '_data', {
|
||
|
value: data,
|
||
|
enumerable: false,
|
||
|
configurable: true,
|
||
|
writable: false
|
||
|
})
|
||
|
}
|
||
|
|
||
|
Object.defineProperty(PseudoMap.prototype, 'size', {
|
||
|
get: function () {
|
||
|
return this._data.size
|
||
|
},
|
||
|
set: function (n) {},
|
||
|
enumerable: true,
|
||
|
configurable: true
|
||
|
})
|
||
|
|
||
|
PseudoMap.prototype.values =
|
||
|
PseudoMap.prototype.keys =
|
||
|
PseudoMap.prototype.entries = function () {
|
||
|
throw new Error('iterators are not implemented in this version')
|
||
|
}
|
||
|
|
||
|
// Either identical, or both NaN
|
||
|
function same (a, b) {
|
||
|
return a === b || a !== a && b !== b
|
||
|
}
|
||
|
|
||
|
function Entry (k, v, i) {
|
||
|
this.key = k
|
||
|
this.value = v
|
||
|
this._index = i
|
||
|
}
|
||
|
|
||
|
function find (data, k) {
|
||
|
for (var i = 0, s = '_' + k, key = s;
|
||
|
hasOwnProperty.call(data, key);
|
||
|
key = s + i++) {
|
||
|
if (same(data[key].key, k))
|
||
|
return data[key]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function set (data, k, v) {
|
||
|
for (var i = 0, s = '_' + k, key = s;
|
||
|
hasOwnProperty.call(data, key);
|
||
|
key = s + i++) {
|
||
|
if (same(data[key].key, k)) {
|
||
|
data[key].value = v
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
data.size++
|
||
|
data[key] = new Entry(k, v, key)
|
||
|
}
|