예제 #1
0
        /*
         * Add current code to the cache
         */
        private CachedCodeEntry CacheCode(CachedCodeEntryKey key)
        {
            CachedCodeEntry newcached = null;

            lock (s_livecode)
            {
                // first look for it in the cache and move it to the head
                for (LinkedListNode <CachedCodeEntry> current = s_livecode.First; current != null; current = current.Next)
                {
                    if (current.Value._key == key)
                    {
                        s_livecode.Remove(current);
                        s_livecode.AddFirst(current);
                        return(current.Value);
                    }
                }

                // it wasn't in the cache, so we'll add a new one.  Shortcut out for the case where cacheSize is zero.
                if (s_cacheSize != 0)
                {
                    newcached = new CachedCodeEntry(key, _capnames, capslist, _code, _caps, capsize, _runnerref, _replref);
                    s_livecode.AddFirst(newcached);
                    if (s_livecode.Count > s_cacheSize)
                    {
                        s_livecode.RemoveLast();
                    }
                }
            }

            return(newcached);
        }
예제 #2
0
        private CachedCodeEntry GetCachedCodeEntryInternal(CachedCodeEntryKey key, bool isToAdd)
        {
            lock (s_cache)
            {
                // first look for it in the cache and move it to the head
                CachedCodeEntry entry = LookupCachedAndPromote(key);
                // it wasn't in the cache, so we'll add a new one
                if (entry == null && isToAdd && s_cacheSize != 0) // check cache size again in case it changed
                {
                    entry = new CachedCodeEntry(key, capnames, capslist, _code, caps, capsize, _runnerref, _replref);
                    // put first in linked list:
                    if (s_cacheFirst != null)
                    {
                        SysDebug.Assert(s_cacheFirst.Next == null);
                        s_cacheFirst.Next = entry;
                        entry.Previous    = s_cacheFirst;
                    }
                    s_cacheFirst = entry;

                    s_cacheCount++;
                    if (s_cacheCount >= CacheDictionarySwitchLimit)
                    {
                        if (s_cacheCount == CacheDictionarySwitchLimit)
                        {
                            FillCacheDictionary();
                        }
                        else
                        {
                            s_cache.Add(key, entry);
                        }
                        SysDebug.Assert(s_cacheCount == s_cache.Count);
                    }

                    // update last in linked list:
                    if (s_cacheLast == null)
                    {
                        s_cacheLast = entry;
                    }
                    else if (s_cacheCount > s_cacheSize) // remove last
                    {
                        CachedCodeEntry last = s_cacheLast;
                        if (s_cacheCount >= CacheDictionarySwitchLimit)
                        {
                            SysDebug.Assert(s_cache[last.Key] == s_cacheLast);
                            s_cache.Remove(last.Key);
                        }

                        SysDebug.Assert(last.Previous == null);
                        SysDebug.Assert(last.Next != null);
                        SysDebug.Assert(last.Next.Previous == last);
                        last.Next.Previous = null;
                        s_cacheLast        = last.Next;
                        s_cacheCount--;
                    }
                }
                return(entry);
            }
        }
예제 #3
0
 public CachedCodeEntry(CachedCodeEntryKey key, Hashtable capnames, string[] capslist, RegexCode code,
                        Hashtable caps, int capsize, ExclusiveReference runner, WeakReference <RegexReplacement> replref)
 {
     Key       = key;
     Capnames  = capnames;
     Capslist  = capslist;
     Code      = code;
     Caps      = caps;
     Capsize   = capsize;
     Runnerref = runner;
     ReplRef   = replref;
 }
예제 #4
0
        [MethodImpl(MethodImplOptions.AggressiveInlining)] // Unprofitable inline - JIT overly pessimistic
        private static bool TryGetCacheValue(CachedCodeEntryKey key, out CachedCodeEntry entry)
        {
            if (s_cacheCount >= CacheDictionarySwitchLimit)
            {
                SysDebug.Assert((s_cacheFirst != null && s_cacheLast != null && s_cache.Count > 0) ||
                                (s_cacheFirst == null && s_cacheLast == null && s_cache.Count == 0),
                                "Linked list and Dict should be synchronized");
                return(s_cache.TryGetValue(key, out entry));
            }

            return(TryGetCacheValueSmall(key, out entry));
        }
예제 #5
0
        internal CachedCodeEntry(CachedCodeEntryKey key, Dictionary <string, int> capnames, String[] capslist, RegexCode code, Dictionary <Int32, Int32> caps, int capsize, ExclusiveReference runner, SharedReference repl)
        {
            _key      = key;
            _capnames = capnames;
            _capslist = capslist;

            _code    = code;
            _caps    = caps;
            _capsize = capsize;

            _runnerref = runner;
            _replref   = repl;
        }
예제 #6
0
        internal CachedCodeEntry(CachedCodeEntryKey key, Hashtable capnames, string[] capslist, RegexCode code, Hashtable caps, int capsize, ExclusiveReference runner, SharedReference repl)
        {
            _key      = key;
            _capnames = capnames;
            _capslist = capslist;

            _code    = code;
            _caps    = caps;
            _capsize = capsize;

            _runnerref = runner;
            _replref   = repl;
        }
예제 #7
0
        private static bool TryGetCacheValueSmall(CachedCodeEntryKey key, out CachedCodeEntry entry)
        {
            entry = s_cacheFirst?.Previous; // first already checked
            while (entry != null)
            {
                if (entry.Key == key)
                {
                    return(true);
                }
                entry = entry.Previous;
            }

            return(false);
        }
예제 #8
0
        private CachedCodeEntry GetCachedCode(CachedCodeEntryKey key, bool isToAdd)
        {
            // to avoid lock:
            CachedCodeEntry first = s_cacheFirst;

            if (first?.Key == key)
            {
                return(first);
            }
            if (s_cacheSize == 0)
            {
                return(null);
            }

            return(GetCachedCodeEntryInternal(key, isToAdd));
        }
예제 #9
0
        /*
         * Find code cache based on options+pattern
         */
        private static CachedCodeEntry LookupCachedAndUpdate(CachedCodeEntryKey key)
        {
            lock (s_livecode)
            {
                for (LinkedListNode <CachedCodeEntry> current = s_livecode.First; current != null; current = current.Next)
                {
                    if (current.Value._key == key)
                    {
                        // If we find an entry in the cache, move it to the head at the same time.
                        s_livecode.Remove(current);
                        s_livecode.AddFirst(current);
                        return(current.Value);
                    }
                }
            }

            return(null);
        }
예제 #10
0
        private static CachedCodeEntry LookupCachedAndPromote(CachedCodeEntryKey key)
        {
            SysDebug.Assert(Monitor.IsEntered(s_cache));
            if (s_cacheFirst?.Key == key) // again check this as could have been promoted by other thread
            {
                return(s_cacheFirst);
            }

            if (TryGetCacheValue(key, out CachedCodeEntry entry))
            {
                // promote:
                SysDebug.Assert(s_cacheFirst != entry, "key should not get s_livecode_first");
                SysDebug.Assert(s_cacheFirst != null, "as Dict has at least one");
                SysDebug.Assert(s_cacheFirst.Next == null);
                SysDebug.Assert(s_cacheFirst.Previous != null);
                SysDebug.Assert(entry.Next != null, "not first so Next should exist");
                SysDebug.Assert(entry.Next.Previous == entry);
                if (s_cacheLast == entry)
                {
                    SysDebug.Assert(entry.Previous == null, "last");
                    s_cacheLast = entry.Next;
                }
                else
                {
                    SysDebug.Assert(entry.Previous != null, "in middle");
                    SysDebug.Assert(entry.Previous.Next == entry);
                    entry.Previous.Next = entry.Next;
                }
                entry.Next.Previous = entry.Previous;

                s_cacheFirst.Next = entry;
                entry.Previous    = s_cacheFirst;
                entry.Next        = null;
                s_cacheFirst      = entry;
            }

            return(entry);
        }
예제 #11
0
        private Regex(string pattern, RegexOptions options, TimeSpan matchTimeout, bool addToCache)
        {
            if (pattern == null)
            {
                throw new ArgumentNullException(nameof(pattern));
            }

            if (options < RegexOptions.None || (((int)options) >> MaxOptionShift) != 0)
            {
                throw new ArgumentOutOfRangeException(nameof(options));
            }

            if ((options & RegexOptions.ECMAScript) != 0 &&
                (options & ~(RegexOptions.ECMAScript |
                             RegexOptions.IgnoreCase |
                             RegexOptions.Multiline |
                             RegexOptions.Compiled |
                             RegexOptions.CultureInvariant
#if DEBUG
                             | RegexOptions.Debug
#endif
                             )) != 0)
            {
                throw new ArgumentOutOfRangeException(nameof(options));
            }

            ValidateMatchTimeout(matchTimeout);

            // After parameter validation assign
            this.pattern         = pattern;
            roptions             = options;
            internalMatchTimeout = matchTimeout;

            // Cache handling. Try to look up this regex in the cache.
            CultureInfo culture = (options & RegexOptions.CultureInvariant) != 0 ?
                                  CultureInfo.InvariantCulture :
                                  CultureInfo.CurrentCulture;
            var             key    = new CachedCodeEntryKey(options, culture.ToString(), pattern);
            CachedCodeEntry cached = GetCachedCode(key, false);

            if (cached == null)
            {
                // Parse the input
                RegexTree tree = RegexParser.Parse(pattern, roptions, culture);

                // Extract the relevant information
                capnames = tree.CapNames;
                capslist = tree.CapsList;
                _code    = RegexWriter.Write(tree);
                caps     = _code.Caps;
                capsize  = _code.CapSize;

                InitializeReferences();

                tree = null;
                if (addToCache)
                {
                    cached = GetCachedCode(key, true);
                }
            }
            else
            {
                caps     = cached.Caps;
                capnames = cached.Capnames;
                capslist = cached.Capslist;
                capsize  = cached.Capsize;
                _code    = cached.Code;
#if FEATURE_COMPILED
                factory = cached.Factory;
#endif

                // Cache runner and replacement
                _runnerref       = cached.Runnerref;
                _replref         = cached.ReplRef;
                _refsInitialized = true;
            }

#if FEATURE_COMPILED
            // if the compile option is set, then compile the code if it's not already
            if (UseOptionC() && factory == null)
            {
                factory = Compile(_code, roptions);

                if (addToCache && cached != null)
                {
                    cached.AddCompiled(factory);
                }

                _code = null;
            }
#endif
        }
예제 #12
0
        private Regex(String pattern, RegexOptions options, TimeSpan matchTimeout, bool useCache)
        {
            RegexTree       tree;
            CachedCodeEntry cached     = null;
            string          cultureKey = null;

            if (pattern == null)
            {
                throw new ArgumentNullException(nameof(pattern));
            }
            if (options < RegexOptions.None || (((int)options) >> MaxOptionShift) != 0)
            {
                throw new ArgumentOutOfRangeException(nameof(options));
            }
            if ((options & RegexOptions.ECMAScript) != 0 &&
                (options & ~(RegexOptions.ECMAScript |
                             RegexOptions.IgnoreCase |
                             RegexOptions.Multiline |
                             RegexOptions.CultureInvariant
#if DEBUG
                             | RegexOptions.Debug
#endif
                             )) != 0)
            {
                throw new ArgumentOutOfRangeException(nameof(options));
            }

            ValidateMatchTimeout(matchTimeout);

            // Try to look up this regex in the cache.  We do this regardless of whether useCache is true since there's
            // really no reason not to.
            if ((options & RegexOptions.CultureInvariant) != 0)
            {
                cultureKey = CultureInfo.InvariantCulture.ToString(); // "English (United States)"
            }
            else
            {
                cultureKey = CultureInfo.CurrentCulture.ToString();
            }

            var key = new CachedCodeEntryKey(options, cultureKey, pattern);
            cached = LookupCachedAndUpdate(key);

            this.pattern = pattern;
            roptions     = options;

            internalMatchTimeout = matchTimeout;

            if (cached == null)
            {
                // Parse the input
                tree = RegexParser.Parse(pattern, roptions);

                // Extract the relevant information
                _capnames = tree._capnames;
                capslist  = tree._capslist;
                _code     = RegexWriter.Write(tree);
                _caps     = _code._caps;
                capsize   = _code._capsize;

                InitializeReferences();

                tree = null;
                if (useCache)
                {
                    cached = CacheCode(key);
                }
            }
            else
            {
                _caps            = cached._caps;
                _capnames        = cached._capnames;
                capslist         = cached._capslist;
                capsize          = cached._capsize;
                _code            = cached._code;
                _runnerref       = cached._runnerref;
                _replref         = cached._replref;
                _refsInitialized = true;
            }
        }