Implement MachineKey.Protect and MachineKey.Unprotect
[mono.git] / mcs / class / System.Web.Mvc2 / System.Web.Mvc / ExpressionUtil / CachedExpressionCompiler.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. All rights reserved.\r
4  *\r
5  * This software is subject to the Microsoft Public License (Ms-PL). \r
6  * A copy of the license can be found in the license.htm file included \r
7  * in this distribution.\r
8  *\r
9  * You must not remove this notice, or any other, from this software.\r
10  *\r
11  * ***************************************************************************/\r
12 \r
13 namespace System.Web.Mvc.ExpressionUtil {\r
14     using System;\r
15     using System.Linq.Expressions;\r
16 \r
17     internal static class CachedExpressionCompiler {\r
18 \r
19         // This is the entry point to the cached expression tree compiler. The processor will perform a series of checks\r
20         // and optimizations in order to return a fully-compiled func as quickly as possible to the caller. If the\r
21         // input expression is particularly obscure, the system will fall back to a slow but correct compilation step.\r
22         public static Func<TModel, TValue> Process<TModel, TValue>(Expression<Func<TModel, TValue>> lambdaExpression) {\r
23             return Processor<TModel, TValue>.GetFunc(lambdaExpression);\r
24         }\r
25 \r
26         private static class Processor<TModel, TValue> {\r
27 \r
28             private static readonly Cache _cache = new Cache();\r
29 \r
30             public static Func<TModel, TValue> GetFunc(Expression<Func<TModel, TValue>> lambdaExpression) {\r
31                 // look for common patterns that don't need to be fingerprinted\r
32                 Func<TModel, TValue> func = GetFuncFastTrack(lambdaExpression);\r
33                 if (func != null) {\r
34                     return func;\r
35                 }\r
36 \r
37                 // not a common pattern, so try fingerprinting (slower, but cached)\r
38                 func = GetFuncFingerprinted(lambdaExpression);\r
39                 if (func != null) {\r
40                     return func;\r
41                 }\r
42 \r
43                 // pattern not recognized by fingerprinting routine, so compile directly (slowest)\r
44                 return GetFuncSlow(lambdaExpression);\r
45             }\r
46 \r
47             private static Func<TModel, TValue> GetFuncFastTrack(Expression<Func<TModel, TValue>> lambdaExpression) {\r
48                 ParameterExpression modelParameter = lambdaExpression.Parameters[0];\r
49                 Expression body = lambdaExpression.Body;\r
50 \r
51                 return FastTrack<TModel, TValue>.GetFunc(modelParameter, body);\r
52             }\r
53 \r
54             private static Func<TModel, TValue> GetFuncFingerprinted(Expression<Func<TModel, TValue>> lambdaExpression) {\r
55                 ParserContext context = ExpressionParser.Parse(lambdaExpression);\r
56                 if (context.Fingerprint == null) {\r
57                     // fingerprinting failed\r
58                     return null;\r
59                 }\r
60 \r
61                 object[] hoistedValues = context.HoistedValues.ToArray();\r
62                 var del = _cache.GetDelegate(context);\r
63                 return model => del(model, hoistedValues);\r
64             }\r
65 \r
66             private static Func<TModel, TValue> GetFuncSlow(Expression<Func<TModel, TValue>> lambdaExpression) {\r
67                 Func<TModel, TValue> del = lambdaExpression.Compile();\r
68                 return del;\r
69             }\r
70 \r
71             private sealed class Cache : ReaderWriterCache<ExpressionFingerprint, CompiledExpressionDelegate<TModel, TValue>> {\r
72                 private static CompiledExpressionDelegate<TModel, TValue> CreateDelegate(ParserContext context) {\r
73                     var bodyExpr = context.Fingerprint.ToExpression(context);\r
74                     var lambdaExpr = Expression.Lambda<CompiledExpressionDelegate<TModel, TValue>>(bodyExpr, context.ModelParameter, ParserContext.HoistedValuesParameter);\r
75                     var del = lambdaExpr.Compile();\r
76                     return del;\r
77                 }\r
78                 public CompiledExpressionDelegate<TModel, TValue> GetDelegate(ParserContext context) {\r
79                     return FetchOrCreateItem(context.Fingerprint, () => CreateDelegate(context));\r
80                 }\r
81             }\r
82 \r
83         }\r
84 \r
85     }\r
86 }\r