pessimism
Version:
A fast HAMT Map intended for KV caching and optimistic updates
323 lines (304 loc) • 8.64 kB
JavaScript
import * as Block from "bs-platform/lib/es6/block.js";
import * as Caml_option from "bs-platform/lib/es6/caml_option.js";
import * as Js_undefined from "bs-platform/lib/es6/js_undefined.js";
function hash(x) {
var length = x.length;
var explode = function (_h, _i) {
while(true) {
var i = _i;
var h = _h;
if (i < length) {
var h2 = ((h << 5) + h | 0) + x.charCodeAt(i) | 0;
_i = i + 1 | 0;
_h = h2;
continue ;
} else {
return h;
}
};
};
var x$1 = explode(5381, 0);
return (x$1 >>> 1) & 1073741824 | x$1 & -1073741825;
}
function arrayRemove(arr, index) {
arr.splice(index, 1);
return /* () */0;
}
function make(param) {
return new Map();
}
function getUndefined(map, k) {
var item = map.get(hash(k));
if (Js_undefined.testAny(item)) {
return undefined;
} else {
switch (item.tag | 0) {
case 0 :
var value = item[/* value */1];
if (item[/* key */0] === k) {
return value;
} else {
return undefined;
}
case 1 :
var match = item[0];
var value$1 = match[/* value */2];
if (match[/* key */0] === k) {
return value$1;
} else {
return undefined;
}
case 2 :
var match$1 = item[0].find((function (param) {
return param[/* key */0] === k;
}));
if (match$1 !== undefined) {
return match$1[/* value */2];
} else {
return undefined;
}
}
}
}
function get(map, k) {
return Caml_option.undefined_to_opt(getUndefined(map, k));
}
function setOptimistic(map, k, v, id) {
var code = hash(k);
var optimistic = id !== 0;
var item = map.get(code);
var newItem;
if (Js_undefined.testAny(item)) {
newItem = optimistic ? /* Chain */Block.__(1, [/* record */[
/* key */k,
/* id */id,
/* value */v,
/* prev */undefined
]]) : /* Raw */Block.__(0, [
/* key */k,
/* value */v
]);
} else {
switch (item.tag | 0) {
case 0 :
var key = item[/* key */0];
var value = item[/* value */1];
if (key === k && !optimistic) {
item[/* value */1] = v;
newItem = item;
} else if (key === k) {
var prev = /* record */[
/* key */key,
/* id */0,
/* value */value,
/* prev */undefined
];
var box = /* record */[
/* key */key,
/* id */id,
/* value */v,
/* prev */prev
];
newItem = /* Chain */Block.__(1, [box]);
} else {
var box$1 = /* record */[
/* key */k,
/* id */id,
/* value */v,
/* prev */undefined
];
var other = /* record */[
/* key */key,
/* id */0,
/* value */value,
/* prev */undefined
];
newItem = /* Collision */Block.__(2, [/* array */[
box$1,
other
]]);
}
break;
case 1 :
var prev$1 = item[0];
var key$1 = prev$1[/* key */0];
if (key$1 === k && !optimistic) {
newItem = /* Raw */Block.__(0, [
/* key */key$1,
/* value */v
]);
} else if (key$1 === k) {
var box$2 = /* record */[
/* key */key$1,
/* id */id,
/* value */v,
/* prev */prev$1
];
newItem = /* Chain */Block.__(1, [box$2]);
} else {
var box$3 = /* record */[
/* key */k,
/* id */id,
/* value */v,
/* prev */undefined
];
newItem = /* Collision */Block.__(2, [/* array */[
box$3,
prev$1
]]);
}
break;
case 2 :
var bucket = item[0];
var index = bucket.findIndex((function (param) {
return param[/* key */0] === k;
}));
if (index > -1) {
var prev$2 = bucket[index];
var box$4 = /* record */[
/* key */k,
/* id */id,
/* value */v,
/* prev */optimistic ? prev$2 : undefined
];
bucket[index] = box$4;
} else {
var box$5 = /* record */[
/* key */k,
/* id */id,
/* value */v,
/* prev */undefined
];
bucket.push(box$5);
}
newItem = item;
break;
}
}
map.set(code, newItem);
return map;
}
function set(map, k, v) {
return setOptimistic(map, k, v, 0);
}
function remove(map, k) {
var code = hash(k);
var item = map.get(code);
if (!Js_undefined.testAny(item)) {
switch (item.tag | 0) {
case 0 :
if (item[/* key */0] === k) {
map.delete(code);
}
break;
case 1 :
if (item[0][/* key */0] === k) {
map.delete(code);
}
break;
case 2 :
var bucket = item[0];
var index = bucket.findIndex((function (param) {
return param[/* key */0] === k;
}));
if (index > -1) {
arrayRemove(bucket, index);
}
break;
}
}
return map;
}
function clearBoxOptimistic(box, optid) {
var filter = function (_x) {
while(true) {
var x = _x;
if (x !== undefined) {
var b = x;
var prev = b[/* prev */3];
if (b[/* id */1] !== optid) {
b[/* prev */3] = filter(b[/* prev */3]);
return x;
} else {
_x = prev;
continue ;
}
} else {
return undefined;
}
};
};
return filter(box);
}
function clearOptimistic(map, optid) {
map.forEach((function (node, code) {
switch (node.tag | 0) {
case 0 :
return /* () */0;
case 1 :
var box = node[0];
if (box[/* id */1] !== 0) {
var match = clearBoxOptimistic(box, optid);
if (match !== undefined) {
map.set(code, /* Chain */Block.__(1, [match]));
return /* () */0;
} else {
map.delete(code);
return /* () */0;
}
} else {
return /* () */0;
}
case 2 :
var bucket = node[0].reduce((function (acc, box) {
if (box[/* id */1] !== 0) {
var match = clearBoxOptimistic(box, optid);
if (match !== undefined) {
acc.push(match);
return acc;
} else {
return acc;
}
} else {
acc.push(box);
return acc;
}
}), /* array */[]);
var len = bucket.length;
if (len !== 1) {
if (len !== 0) {
map.set(code, /* Collision */Block.__(2, [bucket]));
return /* () */0;
} else {
map.delete(code);
return /* () */0;
}
} else {
var box$1 = bucket[0];
var match$1 = box$1[/* id */1];
if (match$1 !== 0) {
map.set(code, /* Chain */Block.__(1, [box$1]));
return /* () */0;
} else {
var value = box$1[/* value */2];
map.set(code, /* Raw */Block.__(0, [
/* key */box$1[/* key */0],
/* value */value
]));
return /* () */0;
}
}
}
}));
return map;
}
export {
make ,
get ,
getUndefined ,
remove ,
set ,
setOptimistic ,
clearOptimistic ,
}
/* No side effect */