public final void evaluate(final boolean inverseDirection, final byte[] ab) {
        requests++;
        lookupDataValid = false; // this is an assertion for a nasty pifall

        if (cache == null) {
            decode(lookupData, inverseDirection, ab);
            if (currentVars == null || currentVars.length != nBuildInVars) {
                currentVars = new float[nBuildInVars];
            }
            evaluateInto(currentVars, 0);
            currentVarOffset = 0;
            return;
        }

        CacheNode cn;
        if (lastCacheNode.ab == ab) {
            cn = lastCacheNode;
        } else {
            probeCacheNode.ab = ab;
            probeCacheNode.hash = Crc32Utils.crc(ab, 0, ab.length);
            cn = (CacheNode) cache.get(probeCacheNode);
        }

        if (cn == null) {
            cachemisses++;

            cn = (CacheNode) cache.removeLru();
            if (cn == null) {
                cn = new CacheNode();
            }
            cn.hash = probeCacheNode.hash;
            cn.ab = ab;
            cache.put(cn);

            if (probeVarSet.vars == null) {
                probeVarSet.vars = new float[2 * nBuildInVars];
            }

            // forward direction
            decode(lookupData, false, ab);
            evaluateInto(probeVarSet.vars, 0);

            // inverse direction
            lookupData[0] = 2; // inverse shortcut: reuse decoding
            evaluateInto(probeVarSet.vars, nBuildInVars);

            probeVarSet.hash = Arrays.hashCode(probeVarSet.vars);

            // unify the result variable set
            VarWrapper vw = (VarWrapper) resultVarCache.get(probeVarSet);
            if (vw == null) {
                vw = (VarWrapper) resultVarCache.removeLru();
                if (vw == null) {
                    vw = new VarWrapper();
                }
                vw.hash = probeVarSet.hash;
                vw.vars = probeVarSet.vars;
                probeVarSet.vars = null;
                resultVarCache.put(vw);
            }
            cn.vars = vw.vars;
        } else {
            if (ab == cn.ab) {
                requests2++;
            }

            cache.touch(cn);
        }

        currentVars = cn.vars;
        currentVarOffset = inverseDirection ? nBuildInVars : 0;
    }
decode a byte-array into a lookup data array
main/src/main/java/cgeo/geocaching/brouter/expressions/BExpressionContext.java