//
// This software is now distributed according to
// the Lesser Gnu Public License. Please see
// http://www.gnu.org/copyleft/lesser.txt for
// the details.
// -- Happy Computing!
//
package com.stevesoft.ewe_pat;
import ewe.util.*;
/** Uses table lookup to match [] type constructs, but
only if it can use a lookup table 256 bits in size.
It is impractical to make a table if it is too large.
*/
public class FastBracket extends Bracket {
int min, max;
BitSet bs;
FastBracket(boolean n) { super(n); }
// This routine can optimize a bracket, possibly
// it will replace it with a FastBracket.
static Bracket process(Bracket b,boolean ignc) {
Vector v = b.v;
b.pv = null;
try {
// Expand out the vector to make separate
// entries for other cases if ignoreCase is
// turned on.
Vector nv = v;
if(ignc) {
nv = new Vector();
for(int i=0;i<v.size();i++) {
Pattern p = (Pattern)v.elementAt(i);
nv.addElement(p);
if(p instanceof oneChar) {
oneChar oc = (oneChar)p;
nv.addElement(new oneChar(oc.altc));
} else if(p instanceof Range) {
Range ra = (Range)p;
nv.addElement(new Range(ra.altlo,ra.althi));
}
}
}
v = nv;
// Bubble sort, make sure elements
// are in order. This will allow us
// to merge them.
for(int i=0;i<v.size()-1;i++) {
for(int j=0;j<v.size()-1;j++) {
char c1 = getl(v.elementAt(j));
char c2 = getl(v.elementAt(j+1));
if(c2 < c1) {
Object o = v.elementAt(j);
v.setElementAt(v.elementAt(j+1),j);
v.setElementAt(o,j+1);
}
}
}
nv = new Vector();
// merge -- remove overlaps
Pattern p = (Pattern)v.elementAt(0);
nv.addElement(p);
for(int i=1;i<v.size();i++) {
if(geth(p)+1 >= getl(v.elementAt(i))) {
Pattern p2 = (Pattern)v.elementAt(i);
char lo = min(getl(p),getl(p2));
char hi = max(geth(p),geth(p2));
nv.setElementAt(p=mkelem(lo,hi),nv.size()-1);
} else {
p = (Pattern)v.elementAt(i);
nv.addElement(p);
}
}
b.v = v = nv;
} catch(RegSyntax e) {
e.printStackTrace();
}
// We don't want these things to be empty.
Vector negv = neg(v);
if(v.size()==1) return b;
if(negv.size()==1) {
b.v = negv;
b.neg = !b.neg;
return b;
}
// Now consider if we can make a FastBracket.
// Uses a BitSet to do a lookup.
FastBracket fb = newbrack(v,b.neg);
if(fb == null)
fb = newbrack(negv,!b.neg);
if(fb != null) {
fb.parent = b.parent;
fb.next = b.next;
return fb;
}
// return the normal Bracket.
return b;
}
// Build a FastBracket and set bits. If this can't
// be done, return null.
final static FastBracket newbrack(Vector v,boolean neg) {
FastBracket fb = new FastBracket(neg);
fb.v = v;
if(v.size()==0) return null;
fb.min = getl(v.elementAt(0));
fb.max = geth(v.elementAt(v.size()-1));
if(fb.max-fb.min <= 256) {
fb.bs = new BitSet(fb.max-fb.min+1);
for(int i=0;i<v.size();i++) {
Object o = v.elementAt(i);
int min0 = getl(o)-fb.min;
int max0 = geth(o)-fb.min;
for(int j=min0;j<=max0;j++)
fb.bs.set(j);
}
return fb;
}
return null;
}
// Negate a sorted Vector. Applying this
// operation twice should yield the same Vector
// back.
final static Vector neg(Vector v) {
try {
Vector nv = new Vector();
if(v.size()==0) {
nv.addElement(new Range((char)0,(char)65535));
return nv;
}
int p0 = getl(v.elementAt(0));
if(p0!=0)
nv.addElement(mkelem((char)0,(char)(p0-1) ));
for(int i=0;i<v.size()-1;i++) {
int hi = getl(v.elementAt(i+1))-1;
int lo = geth(v.elementAt(i))+1;
nv.addElement(mkelem((char)lo,(char)hi));
}
int pN = geth(v.get(v.size()-1));
if(pN != 65535)
nv.addElement(mkelem((char)(pN+1),(char)65535));
return nv;
} catch(RegSyntax rs) {
return null;
}
}
// Make either a Range or oneChar Object, depending on which
// is appropriate.
final static Pattern mkelem(char lo,char hi) throws RegSyntax {
return lo==hi ? (Pattern)(new oneChar(lo)) : (Pattern)(new Range(lo,hi));
}
static final char min(char a,char b) {
return a<b ? a : b;
}
static final char max(char a,char b) {
return a>b ? a : b;
}
// getl -- get lower value of Range object,
// or get value of oneChar object.
final static char getl(Object o) {
Pattern p = (Pattern)o;
if(p instanceof Range)
return ((Range)p).lo;
return ((oneChar)p).c;
}
// geth -- get higher value of Range object,
// or get value of oneChar object.
final static char geth(Object o) {
Pattern p = (Pattern)o;
if(p instanceof Range)
return ((Range)p).hi;
return ((oneChar)p).c;
}
// This is the easy part!
public int matchInternal(int pos,Pthings pt) {
if(pos >= pt.src.length() || Masked(pos,pt)) return -1;
char c = pt.src.charAt(pos);
return (neg ^ (c >= min && c <= max && bs.get(c-min)) ) ?
nextMatch(pos+1,pt) : -1;
}
}