initial commit of BRouter Version 0.98

This commit is contained in:
Arndt Brenschede 2014-01-18 15:29:05 +01:00
parent e4ae2b37d3
commit 91e62f1164
120 changed files with 15382 additions and 0 deletions

View file

@ -0,0 +1,173 @@
package btools.expressions;
final class BExpression
{
private static final int OR_EXP = 10;
private static final int AND_EXP = 11;
private static final int NOT_EXP = 12;
private static final int ADD_EXP = 20;
private static final int MULTIPLY_EXP = 21;
private static final int MAX_EXP = 22;
private static final int SWITCH_EXP = 30;
private static final int ASSIGN_EXP = 31;
private static final int LOOKUP_EXP = 32;
private static final int NUMBER_EXP = 33;
private static final int VARIABLE_EXP = 34;
private static final int DUMPPOS_EXP = 40;
private int typ;
private BExpression op1;
private BExpression op2;
private BExpression op3;
private float numberValue;
private int variableIdx;
private int lookupNameIdx;
private int lookupValueIdx;
// Parse the expression and all subexpression
public static BExpression parse( BExpressionContext ctx, int level ) throws Exception
{
String operator = ctx.parseToken();
if ( operator == null )
{
if ( level == 0 ) return null;
else throw new IllegalArgumentException( "unexpected end of file" );
}
if ( level == 0 )
{
if ( !"assign".equals( operator ) )
{
throw new IllegalArgumentException( "operator " + operator + " is invalid on toplevel (only 'assign' allowed)" );
}
}
BExpression exp = new BExpression();
int nops = 3;
if ( "switch".equals( operator ) )
{
exp.typ = SWITCH_EXP;
}
else
{
nops = 2; // check binary expressions
if ( "or".equals( operator ) )
{
exp.typ = OR_EXP;
}
else if ( "and".equals( operator ) )
{
exp.typ = AND_EXP;
}
else if ( "multiply".equals( operator ) )
{
exp.typ = MULTIPLY_EXP;
}
else if ( "add".equals( operator ) )
{
exp.typ = ADD_EXP;
}
else if ( "max".equals( operator ) )
{
exp.typ = MAX_EXP;
}
else
{
nops = 1; // check unary expressions
if ( "assign".equals( operator ) )
{
if ( level > 0 ) throw new IllegalArgumentException( "assign operator within expression" );
exp.typ = ASSIGN_EXP;
String variable = ctx.parseToken();
if ( variable == null ) throw new IllegalArgumentException( "unexpected end of file" );
exp.variableIdx = ctx.getVariableIdx( variable, true );
if ( exp.variableIdx < ctx.getMinWriteIdx() ) throw new IllegalArgumentException( "cannot assign to readonly variable " + variable );
}
else if ( "not".equals( operator ) )
{
exp.typ = NOT_EXP;
}
else if ( "dumppos".equals( operator ) )
{
exp.typ = DUMPPOS_EXP;
}
else
{
nops = 0; // check elemantary expressions
int idx = operator.indexOf( '=' );
if ( idx >= 0 )
{
exp.typ = LOOKUP_EXP;
String name = operator.substring( 0, idx );
String value = operator.substring( idx+1 );
exp.lookupNameIdx = ctx.getLookupNameIdx( name );
if ( exp.lookupNameIdx < 0 )
{
throw new IllegalArgumentException( "unknown lookup name: " + name );
}
exp.lookupValueIdx = ctx.getLookupValueIdx( exp.lookupNameIdx, value );
if ( exp.lookupValueIdx < 0 )
{
throw new IllegalArgumentException( "unknown lookup value: " + value );
}
}
else if ( (idx = ctx.getVariableIdx( operator, false )) >= 0 )
{
exp.typ = VARIABLE_EXP;
exp.variableIdx = idx;
}
else
{
try
{
exp.numberValue = Float.parseFloat( operator );
exp.typ = NUMBER_EXP;
}
catch( NumberFormatException nfe )
{
throw new IllegalArgumentException( "unknown expression: " + operator );
}
}
}
}
}
// parse operands
if ( nops > 0 ) exp.op1 = BExpression.parse( ctx, level+1 );
if ( nops > 1 ) exp.op2 = BExpression.parse( ctx, level+1 );
if ( nops > 2 ) exp.op3 = BExpression.parse( ctx, level+1 );
return exp;
}
// Evaluate the expression
public float evaluate( BExpressionContext ctx )
{
switch( typ )
{
case OR_EXP: return op1.evaluate(ctx) != 0.f ? 1.f : ( op2.evaluate(ctx) != 0.f ? 1.f : 0.f );
case AND_EXP: return op1.evaluate(ctx) != 0.f ? ( op2.evaluate(ctx) != 0.f ? 1.f : 0.f ) : 0.f;
case ADD_EXP: return op1.evaluate(ctx) + op2.evaluate(ctx);
case MULTIPLY_EXP: return op1.evaluate(ctx) * op2.evaluate(ctx);
case MAX_EXP: return max( op1.evaluate(ctx), op2.evaluate(ctx) );
case SWITCH_EXP: return op1.evaluate(ctx) != 0.f ? op2.evaluate(ctx) : op3.evaluate(ctx);
case ASSIGN_EXP: return ctx.assign( variableIdx, op1.evaluate(ctx) );
case LOOKUP_EXP: return ctx.getLookupMatch( lookupNameIdx, lookupValueIdx );
case NUMBER_EXP: return numberValue;
case VARIABLE_EXP: return ctx.getVariableValue( variableIdx );
case NOT_EXP: return op1.evaluate(ctx) == 0.f ? 1.f : 0.f;
case DUMPPOS_EXP: ctx.expressionWarning( "INFO" ); return op1.evaluate(ctx);
default: throw new IllegalArgumentException( "unknown op-code: " + typ );
}
}
private float max( float v1, float v2 )
{
return v1 > v2 ? v1 : v2;
}
}

View file

@ -0,0 +1,620 @@
// context for simple expression
// context means:
// - the local variables
// - the local variable names
// - the lookup-input variables
package btools.expressions;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
public final class BExpressionContext
{
private static final String CONTEXT_TAG = "---context:";
private static final String VERSION_TAG = "---lookupversion:";
private String context;
private boolean _inOurContext = false;
private BufferedReader _br = null;
private boolean _readerDone = false;
private BExpressionReceiver _receiver;
private Map<String,Integer> lookupNumbers = new HashMap<String,Integer>();
private ArrayList<BExpressionLookupValue[]> lookupValues = new ArrayList<BExpressionLookupValue[]>();
private ArrayList<String> lookupNames = new ArrayList<String>();
private ArrayList<int[]> lookupHistograms = new ArrayList<int[]>();
private boolean lookupDataFrozen = false;
private int[] lookupData = new int[0];
private Map<String,Integer> variableNumbers = new HashMap<String,Integer>();
private float[] variableData;
// hash-cache for function results
private long[] _arrayBitmap;
private int currentHashBucket = -1;
private long currentBitmap = 0;
public List<BExpression> expressionList;
private int minWriteIdx;
// build-in variable indexes for fast access
private int costfactorIdx;
private int turncostIdx;
private int initialcostIdx;
private float[] _arrayCostfactor;
private float[] _arrayTurncost;
private float[] _arrayInitialcost;
public float getCostfactor() { return _arrayCostfactor[currentHashBucket]; }
public float getTurncost() { return _arrayTurncost[currentHashBucket]; }
public float getInitialcost() { return _arrayInitialcost[currentHashBucket]; }
private int linenr;
public short lookupVersion = -1;
public BExpressionContext( String context )
{
this( context, 4096 );
}
/**
* Create an Expression-Context for the given node
*
* @param context global, way or node - context of that instance
* @param hashSize size of hashmap for result caching
*/
public BExpressionContext( String context, int hashSize )
{
this.context = context;
_arrayBitmap = new long[hashSize];
_arrayCostfactor = new float[hashSize];
_arrayTurncost = new float[hashSize];
_arrayInitialcost = new float[hashSize];
}
/**
* encode lookup data to a 64-bit word
*/
public long encode( int[] ld )
{
long w = 0;
for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names
{
int n = lookupValues.get(inum).length - 1;
int d = ld[inum];
if ( n == 2 ) { n = 1; d = d == 2 ? 1 : 0; } // 1-bit encoding for booleans
while( n != 0 ) { n >>= 1; w <<= 1; }
w |= (long)d;
}
return w;
}
/**
* decode a 64-bit word into a lookup data array
*/
public void decode( int[] ld, long w )
{
for( int inum = lookupValues.size()-1; inum >= 0; inum-- ) // loop over lookup names
{
int nv = lookupValues.get(inum).length;
int n = nv == 3 ? 1 : nv-1; // 1-bit encoding for booleans
int m = 0;
long ww = w;
while( n != 0 ) { n >>= 1; ww >>= 1; m = m<<1 | 1; }
int d = (int)(w & m);
if ( nv == 3 && d == 1 ) d = 2; // 1-bit encoding for booleans
ld[inum] = d;
w = ww;
}
}
/**
* much like decode, but just for counting bits
*/
private void countBits()
{
int bits = 0;
for( int inum = lookupValues.size()-1; inum >= 0; inum-- ) // loop over lookup names
{
int nv = lookupValues.get(inum).length;
int n = nv == 3 ? 1 : nv-1; // 1-bit encoding for booleans
while( n != 0 ) { n >>= 1; bits++; }
}
// System.out.println( "context=" + context + ",bits=" + bits + " keys=" + lookupValues.size() );
if ( bits > 64 ) throw new IllegalArgumentException( "lookup table for context " + context + " exceeds 64 bits!" );
}
public String getCsvDescription( long bitmap )
{
StringBuilder sb = new StringBuilder( 200 );
decode( lookupData, bitmap );
for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names
{
BExpressionLookupValue[] va = lookupValues.get(inum);
sb.append( '\t' ).append( va[lookupData[inum]].toString() );
}
return sb.toString();
}
public String getCsvHeader()
{
StringBuilder sb = new StringBuilder( 200 );
for( String name: lookupNames )
{
sb.append( '\t' ).append( name );
}
return sb.toString();
}
public void readMetaData( File lookupsFile )
{
try
{
BufferedReader br = new BufferedReader( new FileReader( lookupsFile ) );
int parsedLines = 0;
boolean ourContext = false;
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
line = line.trim();
if ( line.length() == 0 || line.startsWith( "#" ) ) continue;
if ( line.startsWith( CONTEXT_TAG ) )
{
ourContext = line.substring( CONTEXT_TAG.length() ).equals( context );
continue;
}
if ( line.startsWith( VERSION_TAG ) )
{
lookupVersion = Short.parseShort( line.substring( VERSION_TAG.length() ) );
continue;
}
if ( !ourContext ) continue;
parsedLines++;
StringTokenizer tk = new StringTokenizer( line, " " );
String name = tk.nextToken();
String value = tk.nextToken();
int idx = name.indexOf( ';' );
if ( idx >= 0 ) name = name.substring( 0, idx );
BExpressionLookupValue newValue = addLookupValue( name, value, null );
// add aliases
while( newValue != null && tk.hasMoreTokens() ) newValue.addAlias( tk.nextToken() );
}
br.close();
if ( parsedLines == 0 && !"global".equals(context) )
{
throw new IllegalArgumentException( lookupsFile.getAbsolutePath()
+ " does not contain data for context " + context + " (old version?)" );
}
// post-process metadata:
lookupDataFrozen = true;
countBits();
}
catch( Exception e )
{
throw new RuntimeException( e );
}
}
private void evaluate( int[] lookupData2 )
{
lookupData = lookupData2;
for( BExpression exp: expressionList)
{
exp.evaluate( this );
}
}
private static int[] crctable = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
public void evaluate( long bitmap, BExpressionReceiver receiver )
{
_receiver = receiver;
if ( currentBitmap != bitmap || currentHashBucket < 0 )
{
// calc hash bucket from crc
int crc = 0xFFFFFFFF;
long bm = bitmap;
for( int j=0; j<8; j++ )
{
crc = (crc >>> 8) ^ crctable[(crc ^ (int)bm) & 0xff];
bm >>= 8;
}
int hashSize = _arrayBitmap.length;
currentHashBucket = (crc & 0xfffffff) % hashSize;
currentBitmap = bitmap;
}
if ( _arrayBitmap[currentHashBucket] == bitmap )
{
return;
}
_arrayBitmap[currentHashBucket] = bitmap;
decode( lookupData, bitmap );
evaluate( lookupData );
_arrayCostfactor[currentHashBucket] = variableData[costfactorIdx];
_arrayTurncost[currentHashBucket] = variableData[turncostIdx];
_arrayInitialcost[currentHashBucket] = variableData[initialcostIdx];
_receiver = null;
}
public void dumpStatistics()
{
TreeMap<String,String> counts = new TreeMap<String,String>();
// first count
for( String name: lookupNumbers.keySet() )
{
int cnt = 0;
int inum = lookupNumbers.get(name).intValue();
int[] histo = lookupHistograms.get(inum);
// if ( histo.length == 500 ) continue;
for( int i=2; i<histo.length; i++ )
{
cnt += histo[i];
}
counts.put( "" + ( 1000000000 + cnt) + "_" + name, name );
}
while( counts.size() > 0 )
{
String key = counts.lastEntry().getKey();
String name = counts.get(key);
counts.remove( key );
int inum = lookupNumbers.get(name).intValue();
BExpressionLookupValue[] values = lookupValues.get(inum);
int[] histo = lookupHistograms.get(inum);
if ( values.length == 1000 ) continue;
String[] svalues = new String[values.length];
for( int i=0; i<values.length; i++ )
{
String scnt = "0000000000" + histo[i];
scnt = scnt.substring( scnt.length() - 10 );
svalues[i] = scnt + " " + values[i].toString();
}
Arrays.sort( svalues );
for( int i=svalues.length-1; i>=0; i-- )
{
System.out.println( name + ";" + svalues[i] );
}
}
}
/**
* @return a new lookupData array, or null if no metadata defined
*/
public int[] createNewLookupData()
{
if ( lookupDataFrozen )
{
return new int[lookupValues.size()];
}
return null;
}
/**
* add a new lookup-value for the given name to the given lookupData array.
* If no array is given (null value passed), the value is added to
* the context-binded array. In that case, unknown names and values are
* created dynamically.
*
* @return a newly created value element, if any, to optionally add aliases
*/
public BExpressionLookupValue addLookupValue( String name, String value, int[] lookupData2 )
{
BExpressionLookupValue newValue = null;
Integer num = lookupNumbers.get( name );
if ( num == null )
{
if ( lookupData2 != null )
{
// do not create unknown name for external data array
return newValue;
}
// unknown name, create
num = new Integer( lookupValues.size() );
lookupNumbers.put( name, num );
lookupNames.add( name );
lookupValues.add( new BExpressionLookupValue[]{ new BExpressionLookupValue( "" )
, new BExpressionLookupValue( "unknown" ) } );
lookupHistograms.add( new int[2] );
int[] ndata = new int[lookupData.length+1];
System.arraycopy( lookupData, 0, ndata, 0, lookupData.length );
lookupData = ndata;
}
// look for that value
int inum = num.intValue();
BExpressionLookupValue[] values = lookupValues.get( inum );
int[] histo = lookupHistograms.get( inum );
int i=0;
for( ; i<values.length; i++ )
{
BExpressionLookupValue v = values[i];
if ( v.matches( value ) ) break;
}
if ( i == values.length )
{
if ( lookupData2 != null )
{
// do not create unknown value for external data array,
// record as 'other' instead
lookupData2[inum] = 1;
return newValue;
}
if ( i == 499 )
{
// System.out.println( "value limit reached for: " + name );
}
if ( i == 500 )
{
return newValue;
}
// unknown value, create
BExpressionLookupValue[] nvalues = new BExpressionLookupValue[values.length+1];
int[] nhisto = new int[values.length+1];
System.arraycopy( values, 0, nvalues, 0, values.length );
System.arraycopy( histo, 0, nhisto, 0, histo.length );
values = nvalues;
histo = nhisto;
newValue = new BExpressionLookupValue( value );
values[i] = newValue;
lookupHistograms.set(inum, histo);
lookupValues.set(inum, values);
}
histo[i]++;
// finally remember the actual data
if ( lookupData2 != null ) lookupData2[inum] = i;
else lookupData[inum] = i;
return newValue;
}
public void parseFile( File file, String readOnlyContext )
{
try
{
if ( readOnlyContext != null )
{
linenr = 1;
String realContext = context;
context = readOnlyContext;
expressionList = _parseFile( file );
variableData = new float[variableNumbers.size()];
evaluate( 1L, null );
context = realContext;
}
linenr = 1;
minWriteIdx = variableData == null ? 0 : variableData.length;
costfactorIdx = getVariableIdx( "costfactor", true );
turncostIdx = getVariableIdx( "turncost", true );
initialcostIdx = getVariableIdx( "initialcost", true );
expressionList = _parseFile( file );
float[] readOnlyData = variableData;
variableData = new float[variableNumbers.size()];
for( int i=0; i<minWriteIdx; i++ )
{
variableData[i] = readOnlyData[i];
}
}
catch( Exception e )
{
if ( e instanceof IllegalArgumentException )
{
throw new IllegalArgumentException( "ParseException at line " + linenr + ": " + e.getMessage() );
}
throw new RuntimeException( e );
}
if ( expressionList.size() == 0 )
{
throw new IllegalArgumentException( file.getAbsolutePath()
+ " does not contain expressions for context " + context + " (old version?)" );
}
}
private List<BExpression> _parseFile( File file ) throws Exception
{
_br = new BufferedReader( new FileReader( file ) );
_readerDone = false;
List<BExpression> result = new ArrayList<BExpression>();
for(;;)
{
BExpression exp = BExpression.parse( this, 0 );
if ( exp == null ) break;
result.add( exp );
}
_br.close();
_br = null;
return result;
}
public float getVariableValue( String name, float defaultValue )
{
Integer num = variableNumbers.get( name );
return num == null ? defaultValue : getVariableValue( num.intValue() );
}
public float getVariableValue( String name )
{
Integer num = variableNumbers.get( name );
return num == null ? 0.f : getVariableValue( num.intValue() );
}
public float getVariableValue( int variableIdx )
{
return variableData[variableIdx];
}
public int getVariableIdx( String name, boolean create )
{
Integer num = variableNumbers.get( name );
if ( num == null )
{
if ( create )
{
num = new Integer( variableNumbers.size() );
variableNumbers.put( name, num );
}
else
{
return -1;
}
}
return num.intValue();
}
public int getMinWriteIdx()
{
return minWriteIdx;
}
public float getLookupMatch( int nameIdx, int valueIdx )
{
return lookupData[nameIdx] == valueIdx ? 1.0f : 0.0f;
}
public int getLookupNameIdx( String name )
{
Integer num = lookupNumbers.get( name );
return num == null ? -1 : num.intValue();
}
public int getLookupValueIdx( int nameIdx, String value )
{
BExpressionLookupValue[] values = lookupValues.get( nameIdx );
for( int i=0; i< values.length; i++ )
{
if ( values[i].equals( value ) ) return i;
}
return -1;
}
public String parseToken() throws Exception
{
for(;;)
{
String token = _parseToken();
if ( token == null ) return null;
if ( token.startsWith( CONTEXT_TAG ) )
{
_inOurContext = token.substring( CONTEXT_TAG.length() ).equals( context );
}
else if ( _inOurContext )
{
return token;
}
}
}
private String _parseToken() throws Exception
{
StringBuilder sb = new StringBuilder(32);
boolean inComment = false;
for(;;)
{
int ic = _readerDone ? -1 : _br.read();
if ( ic < 0 )
{
if ( sb.length() == 0 ) return null;
_readerDone = true;
return sb.toString();
}
char c = (char)ic;
if ( c == '\n' ) linenr++;
if ( inComment )
{
if ( c == '\r' || c == '\n' ) inComment = false;
continue;
}
if ( Character.isWhitespace( c ) )
{
if ( sb.length() > 0 ) return sb.toString();
else continue;
}
if ( c == '#' && sb.length() == 0 ) inComment = true;
else sb.append( c );
}
}
public float assign( int variableIdx, float value )
{
variableData[variableIdx] = value;
return value;
}
public void expressionWarning( String message )
{
_arrayBitmap[currentHashBucket] = 0L; // no caching if warnings
if ( _receiver != null ) _receiver.expressionWarning( context, message );
}
}

View file

@ -0,0 +1,66 @@
/**
* A lookup value with optional aliases
*
* toString just gives the primary value,
* equals just compares against primary value
* matches() also compares aliases
*
* @author ab
*/
package btools.expressions;
import java.util.ArrayList;
final class BExpressionLookupValue
{
String value;
ArrayList<String> aliases;
@Override
public String toString()
{
return value;
}
public BExpressionLookupValue( String value )
{
this.value = value;
}
public void addAlias( String alias )
{
if ( aliases == null ) aliases = new ArrayList<String>();
aliases.add( alias );
}
@Override
public boolean equals( Object o )
{
if ( o instanceof String )
{
String v = (String)o;
return value.equals( v );
}
if ( o instanceof BExpressionLookupValue )
{
BExpressionLookupValue v = (BExpressionLookupValue)o;
return value.equals( v.value );
}
return false;
}
public boolean matches( String s )
{
if ( value.equals( s ) ) return true;
if ( aliases != null )
{
for( String alias : aliases )
{
if ( alias.equals( s ) ) return true;
}
}
return false;
}
}

View file

@ -0,0 +1,7 @@
package btools.expressions;
public interface BExpressionReceiver
{
public void expressionWarning( String context, String message );
}