function uniqueIndex(array, keyFn) {
const
index = {},
slotCounts = {},
changeKeys = [],
changeItems = [],
slot = (id) => {
return id in index ? index[id] : index[id] = S.data(null);
};
let changeCount = 0;
const
incKey = (item, key) => {
if (key in slotCounts) slotCounts[key]++
else slotCounts[key] = 1;
changeKeys[changeCount] = key;
changeItems[changeCount] = item;
changeCount++;
},
decKey = (item, key) => {
slotCounts[key]--;
changeKeys[changeCount] = key;
changeItems[changeCount] = UNSET;
changeCount++;
},
changeBuilder = map(array,
(item, oldkey) => {
const key = keyFn(item);
if (key !== oldkey) {
if (oldkey !== undefined) decKey(item, oldkey);
incKey(item, key);
}
return key;
},
decKey
),
updater = S.on(changeBuilder, () => {
let errors = "";
while (changeCount) {
changeCount--;
const
key = changeKeys[changeCount],
item = changeItems[changeCount],
slotCount = slotCounts[key],
_slot = slot(key);
changeItems[changeCount] = UNSET;
if (slotCount === 0) {
_slot(null);
} else if (slotCount === 1) {
if (item !== UNSET) _slot(item);
} else {
if (item !== UNSET) errors += "key: " + key + ", item: " + item + ". ";
slotCounts[key] = 1;
}
}
if (errors) throw new Error("UniqueIndex collision(s): " + errors);
});
return (id) =>
typeof id === 'function' ? () => slot(id())() : slot(id);
}