public void freeze ( ) { /* Construct the rule array and index table. We reorder the * rules by sorting them into 256 bins. Each bin contains all * rules matching the index value for that bin. A rule * matches an index value if string whose first key character * has a low byte equal to the index value can match the rule. * * Each bin contains zero or more rules, in the same order * they were found originally. However, the total rules in * the bins may exceed the number in the original vector, * since rules that have a variable as their first key * character will generally fall into more than one bin. * * That is, each bin contains all rules that either have that * first index value as their first key character, or have * a set containing the index value as their first character. */ int n = ruleVector . size ( ) ; index = new int [ 257 ] ; // [sic] List < TransliterationRule > v = new ArrayList < TransliterationRule > ( 2 * n ) ; // heuristic; adjust as needed /* Precompute the index values. This saves a LOT of time. */ int [ ] indexValue = new int [ n ] ; for ( int j = 0 ; j < n ; ++ j ) { TransliterationRule r = ruleVector . get ( j ) ; indexValue [ j ] = r . getIndexValue ( ) ; } for ( int x = 0 ; x < 256 ; ++ x ) { index [ x ] = v . size ( ) ; for ( int j = 0 ; j < n ; ++ j ) { if ( indexValue [ j ] >= 0 ) { if ( indexValue [ j ] == x ) { v . add ( ruleVector . get ( j ) ) ; } } else { // If the indexValue is < 0, then the first key character is // a set, and we must use the more time-consuming // matchesIndexValue check. In practice this happens // rarely, so we seldom tread this code path. TransliterationRule r = ruleVector . get ( j ) ; if ( r . matchesIndexValue ( x ) ) { v . add ( r ) ; } } } } index [ 256 ] = v . size ( ) ; /* Freeze things into an array. */ rules = new TransliterationRule [ v . size ( ) ] ; v . toArray ( rules ) ; StringBuilder errors = null ; /* Check for masking. This is MUCH faster than our old check, * which was each rule against each following rule, since we * only have to check for masking within each bin now. It's * 256*O(n2^2) instead of O(n1^2), where n1 is the total rule * count, and n2 is the per-bin rule count. But n2<<n1, so * it's a big win. */ for ( int x = 0 ; x < 256 ; ++ x ) { for ( int j = index [ x ] ; j < index [ x + 1 ] - 1 ; ++ j ) { TransliterationRule r1 = rules [ j ] ; for ( int k = j + 1 ; k < index [ x + 1 ] ; ++ k ) { TransliterationRule r2 = rules [ k ] ; if ( r1 . masks ( r2 ) ) { if ( errors == null ) { errors = new StringBuilder ( ) ; } else { errors . append ( "\n" ) ; } errors . append ( "Rule " + r1 + " masks " + r2 ) ; } } } } if ( errors != null ) { throw new IllegalArgumentException ( errors . toString ( ) ) ; } }
Close this rule set to further additions check it for masked rules and index it to optimize performance .