package com.github.lindenb.jvarkit.util.bio.bin;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/** memory safe ucsc-bin iterator */
public class BinIterator implements Iterator<Integer>
{
private final int MAX_GENOME_SIZE=536870912;//2^29
private boolean _has_next_called=false;
private boolean _has_next=false;
private int _next=-1;
private int beg;
private int end;
private int depth=0;
private int k=0;
public BinIterator(int beg0,int end0)
{
if (end0 >= MAX_GENOME_SIZE) end0 = MAX_GENOME_SIZE;
--end0;
this.beg=beg0;
this.end=end0;
}
private boolean shift()
{
if(beg>end) return false;
for(;;)
{
switch(depth)
{
case 0:
_next=0;
depth++;
k= 1 + (beg>>26);
return true;
case 1:
if(k<=1 + (end>>26))
{
_next=k;
++k;
return true;
}
else
{
k=9 + (beg>>23);
++depth;
}
break;
case 2:
if(k<= 9 + (end>>23))
{
_next=k;
++k;
return true;
}
else
{
k= 73 + (beg>>20);
++depth;
}
break;
case 3:
if(k<= 73 + (end>>20))
{
_next=k;
++k;
return true;
}
else
{
k= 585 + (beg>>17);
++depth;
}
break;
case 4:
if(k<= 585 + (end>>17))
{
_next=k;
++k;
return true;
}
else
{
k= 4681 + (beg>>14);
++depth;
}
break;
case 5:
if(k<= 4681 + (end>>14))
{
_next=k;
++k;
return true;
}
else
{
++depth;
return false;
}
default: return false;
}
}
}
public boolean hasNext()
{
if(_has_next_called) return _has_next;
_has_next_called=true;
_has_next=this.shift();
return _has_next;
}
public Integer next()
{
if(!_has_next_called) hasNext();
if(!_has_next) throw new IllegalStateException();
int tmp=_next;
_next=-1;
_has_next_called=false;
_has_next=false;
return tmp;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return "bin("+beg+"-"+(end+1)+")";
}
static public List<Integer> bins(int beg,int end)
{
List<Integer> L=new ArrayList<Integer>();
BinIterator iter=new BinIterator(beg, end);
while(iter.hasNext())
{
L.add(iter.next());
}
return L;
}
public static void main(String[] args)
{
if(args.length!=2)
{
System.err.println("Usage: begin end");
System.exit(-1);
}
try
{
BinIterator iter=new BinIterator(
Integer.parseInt(args[0]),
Integer.parseInt(args[1]));
while(iter.hasNext())
{
System.out.println(iter.next());
}
}
catch(Exception err)
{
err.printStackTrace();
System.exit(-1);
}
}
}