import{assert as l,binarySearchLessOrEqual as g,removeItem as h}from"./misc.js";export class Reader{constructor(e,n=1/0){this.source=e,this.maxStorableBytes=n,this.loadedSegments=[],this.loadingSegments=[],this.sourceSizePromise=null,this.nextAge=0,this.totalStoredBytes=0}async loadRange(e,n){if(n=Math.min(n,await this.source.getSize()),e>=n)return;const i=this.loadingSegments.find(a=>a.start<=e&&a.end>=n);if(i){await i.promise;return}const s=g(this.loadedSegments,e,a=>a.start);if(s!==-1)for(let a=s;a<this.loadedSegments.length;a++){const r=this.loadedSegments[a];if(r.start>e)break;if(r.end>=n)return}this.source.onread?.(e,n);const t=this.source._read(e,n),o={start:e,end:n,promise:t};this.loadingSegments.push(o);const d=await t;h(this.loadingSegments,o),this.insertIntoLoadedSegments(e,d)}rangeIsLoaded(e,n){if(n<=e)return!0;const i=g(this.loadedSegments,e,s=>s.start);if(i===-1)return!1;for(let s=i;s<this.loadedSegments.length;s++){const t=this.loadedSegments[s];if(t.start>e)break;if(t.end>=n)return!0}return!1}insertIntoLoadedSegments(e,n){const i={start:e,end:e+n.byteLength,bytes:n,view:new DataView(n.buffer),age:this.nextAge++};let s=g(this.loadedSegments,e,t=>t.start);(s===-1||this.loadedSegments[s].start<i.start)&&s++,this.loadedSegments.splice(s,0,i),this.totalStoredBytes+=n.byteLength;for(let t=s+1;t<this.loadedSegments.length;t++){const o=this.loadedSegments[t];if(o.start>=i.end)break;i.start<=o.start&&o.end<=i.end&&(this.loadedSegments.splice(t,1),t--)}for(;this.totalStoredBytes>this.maxStorableBytes&&this.loadedSegments.length>1;){let t=null,o=-1;for(let d=0;d<this.loadedSegments.length;d++){const a=this.loadedSegments[d];(!t||a.age<t.age)&&(t=a,o=d)}l(t),this.totalStoredBytes-=t.bytes.byteLength,this.loadedSegments.splice(o,1)}}getViewAndOffset(e,n){const i=g(this.loadedSegments,e,t=>t.start);let s=null;if(i!==-1)for(let t=i;t<this.loadedSegments.length;t++){const o=this.loadedSegments[t];if(o.start>e)break;if(n<=o.end){s=o;break}}if(!s)throw new Error(`No segment loaded for range [${e}, ${n}).`);return s.age=this.nextAge++,{view:s.view,offset:s.bytes.byteOffset+e-s.start}}forgetRange(e,n){if(n<=e)return;const i=g(this.loadedSegments,e,t=>t.start);if(i===-1)return;const s=this.loadedSegments[i];s.start!==e||s.end!==n||(this.loadedSegments.splice(i,1),this.totalStoredBytes-=s.bytes.byteLength)}}
