File: System\Runtime\CompilerServices\RuleCache.cs
Web Access
Project: src\src\libraries\System.Linq.Expressions\src\System.Linq.Expressions.csproj (System.Linq.Expressions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.ComponentModel;
using System.Diagnostics;
using System.Dynamic.Utils;
 
namespace System.Runtime.CompilerServices
{
    /// <summary>
    /// This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.
    /// Represents a cache of runtime binding rules.
    /// </summary>
    /// <typeparam name="T">The delegate type.</typeparam>
    [EditorBrowsable(EditorBrowsableState.Never), DebuggerStepThrough]
    public class RuleCache<T> where T : class
    {
        private T[] _rules = Array.Empty<T>();
        private readonly object _cacheLock = new object();
 
        private const int MaxRules = 128;
 
        internal RuleCache() { }
 
        internal T[] GetRules()
        {
            return _rules;
        }
 
        // move the rule +2 up.
        // this is called on every successful rule.
        internal void MoveRule(T rule, int i)
        {
            // limit search to MaxSearch elements.
            // Rule should not get too far unless it has been already moved up.
            // need a lock to make sure we are moving the right rule and not losing any.
            lock (_cacheLock)
            {
                const int MaxSearch = 8;
                int count = _rules.Length - i;
                if (count > MaxSearch)
                {
                    count = MaxSearch;
                }
 
                int oldIndex = -1;
                int max = Math.Min(_rules.Length, i + count);
                for (int index = i; index < max; index++)
                {
                    if (_rules[index] == rule)
                    {
                        oldIndex = index;
                        break;
                    }
                }
                if (oldIndex < 2)
                {
                    return;
                }
                T oldRule = _rules[oldIndex];
                _rules[oldIndex] = _rules[oldIndex - 1];
                _rules[oldIndex - 1] = _rules[oldIndex - 2];
                _rules[oldIndex - 2] = oldRule;
            }
        }
 
        internal void AddRule(T newRule)
        {
            // need a lock to make sure we are not losing rules.
            lock (_cacheLock)
            {
                _rules = AddOrInsert(_rules, newRule);
            }
        }
 
        // Adds to end or inserts items at InsertPosition
        private const int InsertPosition = MaxRules / 2;
 
        private static T[] AddOrInsert(T[] rules, T item)
        {
            if (rules.Length < InsertPosition)
            {
                return rules.AddLast(item);
            }
 
            T[] newRules;
 
            int newLength = rules.Length + 1;
            if (newLength > MaxRules)
            {
                newLength = MaxRules;
                newRules = rules;
            }
            else
            {
                newRules = new T[newLength];
                Array.Copy(rules, newRules, InsertPosition);
            }
 
            newRules[InsertPosition] = item;
            Array.Copy(rules, InsertPosition, newRules, InsertPosition + 1, newLength - InsertPosition - 1);
            return newRules;
        }
    }
}