2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Actions / RuleCache.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Microsoft Public License. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Microsoft Public License, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Microsoft Public License.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15 using System; using Microsoft;
16
17
18 using System.ComponentModel;
19 using System.Diagnostics;
20 #if CODEPLEX_40
21 using System.Dynamic.Utils;
22 #else
23 using Microsoft.Scripting.Utils;
24 #endif
25
26 #if CODEPLEX_40
27 namespace System.Runtime.CompilerServices {
28 #else
29 namespace Microsoft.Runtime.CompilerServices {
30 #endif
31     /// <summary>
32     /// This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.
33     /// Represents a cache of runtime binding rules.
34     /// </summary>
35     /// <typeparam name="T">The delegate type.</typeparam>
36     [EditorBrowsable(EditorBrowsableState.Never), DebuggerStepThrough]
37     public class RuleCache<T> where T : class {
38         private T[] _rules = new T[0];
39         private readonly Object cacheLock = new Object();
40
41         private const int MaxRules = 128;
42
43         internal RuleCache() { }
44
45         internal T[] GetRules() {
46             return _rules;
47         }
48
49         // move the rule +2 up.
50         // this is called on every successful rule.
51         internal void MoveRule(T rule, int i) {
52             // limit search to MaxSearch elements. 
53             // Rule should not get too far unless it has been already moved up.
54             // need a lock to make sure we are moving the right rule and not loosing any.
55             lock (cacheLock) {
56                 const int MaxSearch = 8;
57                 int count = _rules.Length - i;
58                 if (count > MaxSearch) {
59                     count = MaxSearch;
60                 }
61
62                 int oldIndex = -1;
63                 int max = Math.Min(_rules.Length, i + count);
64                 for (int index = i; index < max; index++) {
65                     if (_rules[index] == rule) {
66                         oldIndex = index;
67                         break;
68                     }
69                 }
70                 if (oldIndex < 0) {
71                     return;
72                 }
73                 T oldRule = _rules[oldIndex];
74                 _rules[oldIndex] = _rules[oldIndex - 1];
75                 _rules[oldIndex - 1] = _rules[oldIndex - 2];
76                 _rules[oldIndex - 2] = oldRule;
77             }
78         }
79
80         internal void AddRule(T newRule) {
81             // need a lock to make sure we are not loosing rules.
82             lock (cacheLock) {
83                 _rules = AddOrInsert(_rules, newRule);
84             }
85         }
86
87         internal void ReplaceRule(T oldRule, T newRule) {
88             // need a lock to make sure we are replacing the right rule
89             lock (cacheLock) {
90                 int i = Array.IndexOf(_rules, oldRule);
91                 if (i >= 0) {
92                     _rules[i] = newRule;
93                     return; // DONE
94                 }
95
96                 // could not find it.
97                 _rules = AddOrInsert(_rules, newRule);
98             }
99         }
100
101
102         // Adds to end or or inserts items at InsertPosition
103         private const int InsertPosition = MaxRules / 2;
104
105         private static T[] AddOrInsert(T[] rules, T item) {
106             if (rules.Length < InsertPosition) {
107                 return rules.AddLast(item);
108             }
109
110             T[] newRules;
111
112             int newLength = rules.Length + 1;
113             if (newLength > MaxRules) {
114                 newLength = MaxRules;
115                 newRules = rules;
116             } else {
117                 newRules = new T[newLength];
118             }
119
120             Array.Copy(rules, 0, newRules, 0, InsertPosition);
121             newRules[InsertPosition] = item;
122             Array.Copy(rules, InsertPosition, newRules, InsertPosition + 1, newLength - InsertPosition - 1);
123             return newRules;
124         }
125     }
126 }