114 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 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)
 | |
| }
 |