예제 #1
0
        /// <summary>
        /// Build DFAs from a provided NFA
        ///
        /// This method is used when you want to build the NFA yourself instead of letting this class do it.
        ///
        /// Languages built simultaneously will be globally minimized and will share as many states as possible.
        /// </summary>
        /// <param name="nfa">The NFA</param>
        /// <param name="nfaStartStates">The return value will include the DFA states corresponding to these NFA states, in the same order</param>
        /// <param name="ambiguityResolver">When patterns for multiple results match the same string, this is called to
        /// combine the multiple results into one.  If this is null, then a DfaAmbiguityException will be thrown in that case.</param>
        /// <param name="cache">If this cache is non-null, it will be checked for a memoized result for this NFA, and will be populated
        /// with a memoized result when the call is complete.</param>
        /// <returns>DFA start states that are equivalent to the given NFA start states.  This will have the same length as nfaStartStates, with
        /// corresponding start states in corresponding positions.</returns>
        public static IList <DfaState <TResult> > BuildFromNfa(Nfa <TResult> nfa, int[] nfaStartStates, DfaAmbiguityResolver <TResult> ambiguityResolver,
                                                               IBuilderCache cache)
        {
            string cacheKey = null;
            SerializableDfa <TResult> serializableDfa = null;

            if (cache != null)
            {
                var hashAlg = new SHA256Managed();
                using (var ms = new MemoryStream())
                {
                    using var cs = new CryptoStream(ms, hashAlg, CryptoStreamMode.Write);
                    var bf = new BinaryFormatter();
                    bf.Serialize(ms, nfaStartStates);
                    bf.Serialize(ms, nfa);
                    bf.Serialize(ms, ambiguityResolver);
                    ms.Flush();
                    cs.FlushFinalBlock();

                    cacheKey = Base32.GetDigest(hashAlg.Hash);
                }

                serializableDfa = (SerializableDfa <TResult>)cache.GetCachedItem(cacheKey);
            }

            if (serializableDfa == null)
            {
                var rawDfa     = new DfaFromNfa <TResult>(nfa, nfaStartStates, ambiguityResolver).GetDfa();
                var minimalDfa = new DfaMinimizer <TResult>(rawDfa).GetMinimizedDfa();
                serializableDfa = new SerializableDfa <TResult>(minimalDfa);
                if (cacheKey != null)
                {
                    cache.MaybeCacheItem(cacheKey, serializableDfa);
                }
            }

            return(serializableDfa.GetStartStates());
        }
예제 #2
0
        private string GetCacheKey(int dfaType, IList <ISet <TResult> > languages, DfaAmbiguityResolver <TResult> ambiguityResolver)
        {
            string cacheKey;
            var    hashAlg = new SHA256Managed();

            using (var ms = new MemoryStream())
            {
                using var cs = new CryptoStream(ms, hashAlg, CryptoStreamMode.Write);
                var bf = new BinaryFormatter();
                bf.Serialize(ms, dfaType);
                var numLangs = languages.Count;
                bf.Serialize(ms, numLangs);

                //write key stuff out in an order based on our LinkedHashMap, for deterministic serialization
                foreach (var patEntry in patterns)
                {
                    var included = false;
                    var patList  = patEntry.Value;
                    if (patList.Count == 0)
                    {
                        continue;
                    }

                    for (var i = 0; i < numLangs; ++i)
                    {
                        if (!languages[i].Contains(patEntry.Key))
                        {
                            continue;
                        }

                        included = true;
                        break;
                    }

                    if (!included)
                    {
                        continue;
                    }

                    bf.Serialize(ms, patList.Count);
                    if (numLangs > 1)
                    {
                        var bits = languages[0].Contains(patEntry.Key) ? 1 : 0;
                        for (var i = 1; i < languages.Count; ++i)
                        {
                            if ((i & 31) == 0)
                            {
                                bf.Serialize(ms, bits);
                                bits = 0;
                            }

                            if (languages[i].Contains(patEntry.Key))
                            {
                                bits |= 1 << (i & 31);
                            }
                        }

                        bf.Serialize(ms, bits);
                    }

                    foreach (var pat in patList)
                    {
                        bf.Serialize(ms, pat);
                    }

                    bf.Serialize(ms, patEntry.Key);
                }

                bf.Serialize(ms, 0); //0-size pattern list terminates pattern map
                bf.Serialize(ms, ambiguityResolver ?? (object)0);
                ms.Flush();
                cs.FlushFinalBlock();

                cacheKey = Base32.GetDigest(hashAlg.Hash);
            }

            return(cacheKey);
        }