mirror of
https://github.com/Doodle3D/Doodle3D-API
synced 2024-12-23 14:13:47 +01:00
156 lines
4.0 KiB
JavaScript
156 lines
4.0 KiB
JavaScript
/* */
|
|
'use strict';
|
|
var $ = require("./$"),
|
|
ctx = require("./$.ctx"),
|
|
safe = require("./$.uid").safe,
|
|
assert = require("./$.assert"),
|
|
forOf = require("./$.for-of"),
|
|
step = require("./$.iter").step,
|
|
$has = $.has,
|
|
set = $.set,
|
|
isObject = $.isObject,
|
|
hide = $.hide,
|
|
isExtensible = Object.isExtensible || isObject,
|
|
ID = safe('id'),
|
|
O1 = safe('O1'),
|
|
LAST = safe('last'),
|
|
FIRST = safe('first'),
|
|
ITER = safe('iter'),
|
|
SIZE = $.DESC ? safe('size') : 'size',
|
|
id = 0;
|
|
function fastKey(it, create) {
|
|
if (!isObject(it))
|
|
return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
|
|
if (!$has(it, ID)) {
|
|
if (!isExtensible(it))
|
|
return 'F';
|
|
if (!create)
|
|
return 'E';
|
|
hide(it, ID, ++id);
|
|
}
|
|
return 'O' + it[ID];
|
|
}
|
|
function getEntry(that, key) {
|
|
var index = fastKey(key),
|
|
entry;
|
|
if (index !== 'F')
|
|
return that[O1][index];
|
|
for (entry = that[FIRST]; entry; entry = entry.n) {
|
|
if (entry.k == key)
|
|
return entry;
|
|
}
|
|
}
|
|
module.exports = {
|
|
getConstructor: function(wrapper, NAME, IS_MAP, ADDER) {
|
|
var C = wrapper(function(that, iterable) {
|
|
assert.inst(that, C, NAME);
|
|
set(that, O1, $.create(null));
|
|
set(that, SIZE, 0);
|
|
set(that, LAST, undefined);
|
|
set(that, FIRST, undefined);
|
|
if (iterable != undefined)
|
|
forOf(iterable, IS_MAP, that[ADDER], that);
|
|
});
|
|
require("./$.mix")(C.prototype, {
|
|
clear: function clear() {
|
|
for (var that = this,
|
|
data = that[O1],
|
|
entry = that[FIRST]; entry; entry = entry.n) {
|
|
entry.r = true;
|
|
if (entry.p)
|
|
entry.p = entry.p.n = undefined;
|
|
delete data[entry.i];
|
|
}
|
|
that[FIRST] = that[LAST] = undefined;
|
|
that[SIZE] = 0;
|
|
},
|
|
'delete': function(key) {
|
|
var that = this,
|
|
entry = getEntry(that, key);
|
|
if (entry) {
|
|
var next = entry.n,
|
|
prev = entry.p;
|
|
delete that[O1][entry.i];
|
|
entry.r = true;
|
|
if (prev)
|
|
prev.n = next;
|
|
if (next)
|
|
next.p = prev;
|
|
if (that[FIRST] == entry)
|
|
that[FIRST] = next;
|
|
if (that[LAST] == entry)
|
|
that[LAST] = prev;
|
|
that[SIZE]--;
|
|
}
|
|
return !!entry;
|
|
},
|
|
forEach: function forEach(callbackfn) {
|
|
var f = ctx(callbackfn, arguments[1], 3),
|
|
entry;
|
|
while (entry = entry ? entry.n : this[FIRST]) {
|
|
f(entry.v, entry.k, this);
|
|
while (entry && entry.r)
|
|
entry = entry.p;
|
|
}
|
|
},
|
|
has: function has(key) {
|
|
return !!getEntry(this, key);
|
|
}
|
|
});
|
|
if ($.DESC)
|
|
$.setDesc(C.prototype, 'size', {get: function() {
|
|
return assert.def(this[SIZE]);
|
|
}});
|
|
return C;
|
|
},
|
|
def: function(that, key, value) {
|
|
var entry = getEntry(that, key),
|
|
prev,
|
|
index;
|
|
if (entry) {
|
|
entry.v = value;
|
|
} else {
|
|
that[LAST] = entry = {
|
|
i: index = fastKey(key, true),
|
|
k: key,
|
|
v: value,
|
|
p: prev = that[LAST],
|
|
n: undefined,
|
|
r: false
|
|
};
|
|
if (!that[FIRST])
|
|
that[FIRST] = entry;
|
|
if (prev)
|
|
prev.n = entry;
|
|
that[SIZE]++;
|
|
if (index !== 'F')
|
|
that[O1][index] = entry;
|
|
}
|
|
return that;
|
|
},
|
|
getEntry: getEntry,
|
|
setIter: function(C, NAME, IS_MAP) {
|
|
require("./$.iter-define")(C, NAME, function(iterated, kind) {
|
|
set(this, ITER, {
|
|
o: iterated,
|
|
k: kind
|
|
});
|
|
}, function() {
|
|
var iter = this[ITER],
|
|
kind = iter.k,
|
|
entry = iter.l;
|
|
while (entry && entry.r)
|
|
entry = entry.p;
|
|
if (!iter.o || !(iter.l = entry = entry ? entry.n : iter.o[FIRST])) {
|
|
iter.o = undefined;
|
|
return step(1);
|
|
}
|
|
if (kind == 'keys')
|
|
return step(0, entry.k);
|
|
if (kind == 'values')
|
|
return step(0, entry.v);
|
|
return step(0, [entry.k, entry.v]);
|
|
}, IS_MAP ? 'entries' : 'values', !IS_MAP, true);
|
|
}
|
|
};
|