@tylerbu/sorted-btree-es6
Version:
A sorted list of key-value pairs in a fast, typed in-memory B+ tree with a powerful API.
2 lines (1 loc) • 7.84 kB
JavaScript
Object.defineProperty(exports,"__esModule",{value:!0}),exports.decompose=decompose,exports.buildFromDecomposition=buildFromDecomposition;let b_tree_1=require("../b+tree"),shared_1=require("./shared"),parallelWalk_1=require("./parallelWalk"),decomposeLoadFactor=.7;function decompose(e,a,l,t=!1){let r=e._maxNodeSize,n=e._compare,i=((0,b_tree_1.check)(0<e._root.size()&&0<a._root.size(),"decompose requires non-empty inputs"),[]),s=[],o=[],d=[],p=-1,h=-1,u=void 0,f=Math.floor(r/2),c=e=>{var a=e.keys.length<f?-1:0;i.push(a),s.push(e)},g=(e,a)=>{(0,shared_1.makeLeavesFrom)(o,d,r,decomposeLoadFactor,c),o.length=0,d.length=0,e.isLeaf&&e.keys.length<f?(i.push(-1),s.push(e.clone())):(e.isShared=!0,i.push(a),s.push(e)),a>h&&(p=i.length-1,h=a)},v=()=>{void 0!==u&&(g(u.node,u.height),u=void 0)},y=(e,a)=>{var l=e.spine;for(let e=a;0<=e;--e){var t=l[e].payload;if(t.disqualified)break;t.disqualified=!0}};var _=()=>({disqualified:!1});let k=(e,a,l)=>{var t=e.keys,r=e.values;for(let e=a;e<l;++e)o.push(t[e]),d.push(r[e])};var m=(e,a,l,t,r)=>{(0,b_tree_1.check)(!0===a.disqualified,"onMoveInLeaf: leaf must be disqualified");a=r?l+1:l;a<t&&k(e,a,t)},x=(e,a,l,t,r)=>{u=void 0,a.disqualified?(a=t?l+1:l)<(t=e.keys.length)&&k(e,a,t):(u={node:e,height:0},0===r.spine.length&&v())},I=(e,a,l,t,r,i,n)=>{var s=e.children,o=a-1;if(i!=i||i===Number.POSITIVE_INFINITY)if(l.disqualified){v();var d=s.length;for(let e=t+1;e<d;++e)g(s[e],o)}else if(i===Number.POSITIVE_INFINITY){if(e.keys.length<f)for(let e=t;e<s.length;++e)g(s[e],o);else g(e,a);u=void 0}else u={node:e,height:a};else{0<i&&y(n,r),v();for(let e=t+1;e<i;++e)g(s[e],o)}},b=(e,a,l,t,r)=>{if(0<t){y(r,l);var i=e.children,n=a-1;for(let e=0;e<t;++e)g(i[e],n)}},L=(e,a,l,t)=>{(0<a||(0,b_tree_1.areOverlapping)(e.minKey(),e.maxKey(),(0,parallelWalk_1.getKey)(t),t.leaf.maxKey(),n))&&(l.leafPayload.disqualified=!0,t.leafPayload.disqualified=!0,y(l,l.spine.length-1),y(t,t.spine.length-1),k(e,0,a))},S=e._root.maxKey(),K=a._root.maxKey(),W=0<=n(S,K)?S:K,F=(0,parallelWalk_1.createCursor)(e,_,L,m,x,I,b);let N;if(t){let e={disqualified:!0};N=(0,parallelWalk_1.createCursor)(a,()=>e,(e,a,l,t)=>{(0<a||(0,b_tree_1.areOverlapping)(e.minKey(),e.maxKey(),(0,parallelWalk_1.getKey)(t),t.leaf.maxKey(),n))&&(t.leafPayload.disqualified=!0,y(t,t.spine.length-1))},parallelWalk_1.noop,parallelWalk_1.noop,(e,a,l,t,r,i,n)=>{0<i&&y(n,r)},(e,a,l,t,r)=>{0<t&&y(r,l)})}else N=(0,parallelWalk_1.createCursor)(a,_,L,m,x,I,b);S=(a,e)=>{var l=(0,parallelWalk_1.getKey)(a),t=(0,parallelWalk_1.getKey)(e),r=e.leaf.maxKey();(0,b_tree_1.areOverlapping)(l,a.leaf.maxKey(),t,r,n)&&(a.leafPayload.disqualified=!0);for(let e=0;e<a.spine.length;++e){var i=a.spine[e];(0,b_tree_1.areOverlapping)(l,i.node.maxKey(),t,r,n)&&(i.payload.disqualified=!0)}};S(F,N),S(N,F);let O=F,q=N,M=n((0,parallelWalk_1.getKey)(O),(0,parallelWalk_1.getKey)(q));for(;;){var R=0===M;if(R){var z=(0,parallelWalk_1.getKey)(O),w=l(z,F.leaf.values[F.leafIndex],N.leaf.values[N.leafIndex]),z=(void 0!==w&&(o.push(z),d.push(w)),(0,parallelWalk_1.moveForwardOne)(q,O)),w=(0,parallelWalk_1.moveForwardOne)(O,q);if(z||w){z&&w||(z?(0,parallelWalk_1.moveTo)(O,q,W,!1,!1):(0,parallelWalk_1.moveTo)(q,O,W,!1,!1));break}M=n((0,parallelWalk_1.getKey)(O),(0,parallelWalk_1.getKey)(q))}else{M<0&&(w=q,q=O,O=w);var[z,C]=(0,parallelWalk_1.moveTo)(q,O,(0,parallelWalk_1.getKey)(O),!0,R);if(z){(0,parallelWalk_1.moveTo)(O,q,W,!1,R);break}M=C?0:-1}}return(0,shared_1.makeLeavesFrom)(o,d,r,decomposeLoadFactor,c),h<0&&0<i.length&&(p=0),{heights:i,nodes:s,tallestIndex:p}}function buildFromDecomposition(e,a,l,t,r){var{heights:l,nodes:i,tallestIndex:n}=l,s=((0,b_tree_1.check)(l.length===i.length,"Decompose result has mismatched heights and nodes."),l.length),o=[i[n]],d={branchingFactor:a,spine:o,sideIndex:getRightmostIndex,sideInsertionIndex:getRightInsertionIndex,splitOffSide:splitOffRightSide,balanceLeaves:balanceLeavesRight,updateMax:updateRightMax,mergeLeaves:mergeRightEntries},s=(n+1<=s-1&&(updateFrontier(d,0),processSide(l,i,n+1,s,1,d)),{branchingFactor:a,spine:o,sideIndex:getLeftmostIndex,sideInsertionIndex:getLeftmostIndex,splitOffSide:splitOffLeftSide,balanceLeaves:balanceLeavesLeft,updateMax:parallelWalk_1.noop,mergeLeaves:mergeLeftEntries}),d=(0<=n-1&&(updateFrontier(s,0),processSide(l,i,n-1,-1,-1,s)),new e(void 0,t,r));return d._root=o[0],d}function processSide(i,n,e,a,l,s){var{spine:o,sideIndex:t}=s;let d=0,r=o[0];for(;!r.isShared&&d<o.length-1;)d++,r=r.children[t(r)];var p=new Array(o.length).fill(0);for(let r=e;r!=a;r+=l){var h=o.length-1,u=n[r],f=i[r],c=-1===f,h=((0,b_tree_1.check)(f<=h,"Subtree taller than spine during reconstruction."),h-(f+1));ensureNotShared(s,d,h);let e,a;c?((0,b_tree_1.check)(!0!==u.isShared),e=a=u.keys.length):(e=1,a=u.size());f=findSplitCascadeEndDepth(s,h,e),f=Math.max(0,f);updateSizeAndMax(s,p,d,f);let l=void 0,t;t=c?(l=splitUpwardsAndInsertEntries(s,h,u),h-1):([l]=splitUpwardsAndInsert(s,h,u),h),l&&(o[0]=l,p.push(0),t++),d=t+1,p[t]+=a,updateFrontier(s,f),(0,b_tree_1.check)(d===o.length-1||!0===o[d].isShared,"Non-leaf subtrees must be shared."),(0,b_tree_1.check)(p.length===o.length,"Unflushed sizes length mismatch after root split.")}updateSizeAndMax(s,p,d,0)}function splitUpwardsAndInsert(r,i,n){var{spine:s,branchingFactor:o,sideIndex:d,sideInsertionIndex:p,splitOffSide:h,updateMax:u}=r;if(0<=i){let e=void 0,a=s[i],l=(a.keys.length===o&&(a=e=h(a)),i-1);for(;e&&0<=l;){var f=s[l],c=d(f);u(f,f.children[c].maxKey()),e=f.keys.length<o?void insertNoCount(f,p(f),e):(insertNoCount(c=h(f),p(c),e),c),l--}let t=void 0;return void 0!==e&&(r=s[0],insertNoCount(t=new b_tree_1.BNodeInternal([r],r.size()+e.size()),p(t),e)),insertNoCount(a,p(a),n),[t,a]}return i=s[0],insertNoCount(r=new b_tree_1.BNodeInternal([i],i.size()),p(r),n),[r,r]}function splitUpwardsAndInsertEntries(e,a,l){var{branchingFactor:t,spine:r,balanceLeaves:i,mergeLeaves:n}=e,s=l.keys.length,r=r[a];if(!(r.keys.length+s<=t))return[e,a]=splitUpwardsAndInsert(e,a-1,l),i(a,l,Math.floor(t/2)-s),e;n(r,l)}function ensureNotShared(e,a,l){var{spine:t,sideIndex:r}=e;if(!(l<0)){0===a&&(e=t[0],t[0]=e.clone());for(let e=Math.max(a,1);e<=l;e++){var i=t[e-1],n=r(i),s=i.children[n].clone();i.children[n]=s,t[e]=s}}}function updateSizeAndMax(e,a,l,t){var{spine:r,updateMax:i}=e,n=r[l].maxKey();for(let e=l-1;e>=t;e--){var s=a[e],o=((a[e]=0)<e&&(a[e-1]+=s),r[e]);o._size+=s,i(o,n)}}function updateFrontier(l,t){var{spine:r,sideIndex:i}=l,l=((0,b_tree_1.check)(r.length>t,"updateFrontier: depthLastValid exceeds frontier height"),r[t]);if(!l.isLeaf){let e=l.children[i(l)],a=t+1;for(;!e.isLeaf;){var n=e;r[a]=n,e=n.children[i(n)],a++}r[a]=e}}function findSplitCascadeEndDepth(e,a,l){var{spine:t,branchingFactor:r}=e;if(0<=a){let e=a;if(t[e].keys.length+l<=r)return e;for(e--;0<=e;){if(t[e].keys.length<r)return e;e--}}return-1}function insertNoCount(e,a,l){e.children.splice(a,0,l),e.keys.splice(a,0,l.maxKey())}function getLeftmostIndex(){return 0}function getRightmostIndex(e){return e.children.length-1}function getRightInsertionIndex(e){return e.children.length}function splitOffRightSide(e){return e.splitOffRightSide()}function splitOffLeftSide(e){return e.splitOffLeftSide()}function balanceLeavesRight(e,a,l){var t=e.children.length-2,r=e.children[t],l=r.keys.length-l,i=r.keys.splice(l),l=r.values.splice(l);a.keys.unshift.apply(a.keys,i),a.values.unshift.apply(a.values,l),e.keys[t]=r.maxKey()}function balanceLeavesLeft(e,a,l){var t=e.children[1],r=t.keys.splice(0,l),t=t.values.splice(0,l);a.keys.push.apply(a.keys,r),a.values.push.apply(a.values,t),e.keys[0]=a.maxKey()}function updateRightMax(e,a){e.keys[e.keys.length-1]=a}function mergeRightEntries(e,a){e.keys.push.apply(e.keys,a.keys),e.values.push.apply(e.values,a.values)}function mergeLeftEntries(e,a){e.keys.unshift.apply(e.keys,a.keys),e.values.unshift.apply(e.values,a.values)}