2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / VariantArray.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 #if !SILVERLIGHT // ComObject
19
20 using System.Collections.Generic;
21 using System.Diagnostics;
22 using System.Globalization;
23 #if CODEPLEX_40
24 using System.Linq.Expressions;
25 #else
26 using Microsoft.Linq.Expressions;
27 #endif
28 using System.Reflection;
29 using System.Reflection.Emit;
30 using System.Runtime.InteropServices;
31
32 #if CODEPLEX_40
33 namespace System.Dynamic {
34 #else
35 namespace Microsoft.Scripting {
36 #endif
37
38     [StructLayout(LayoutKind.Sequential)]
39     internal struct VariantArray1 {
40         public Variant Element0;
41     }
42
43     [StructLayout(LayoutKind.Sequential)]
44     internal struct VariantArray2 {
45         public Variant Element0, Element1;
46     }
47
48     [StructLayout(LayoutKind.Sequential)]
49     internal struct VariantArray4 {
50         public Variant Element0, Element1, Element2, Element3;
51     }
52
53     [StructLayout(LayoutKind.Sequential)]
54     internal struct VariantArray8 {
55         public Variant Element0, Element1, Element2, Element3, Element4, Element5, Element6, Element7;
56     }
57
58     //
59     // Helper for getting the right VariantArray struct for a given number of
60     // arguments. Will generate a struct if needed.
61     //
62     // We use this because we don't have stackalloc or pinning in Expression
63     // Trees, so we can't create an array of Variants directly.
64     //
65     internal static class VariantArray {
66         // Don't need a dictionary for this, it will have very few elements
67         // (guarenteed less than 28, in practice 0-2)
68         private static readonly List<Type> _generatedTypes = new List<Type>(0);
69
70         internal static MemberExpression GetStructField(ParameterExpression variantArray, int field) {
71             return Expression.Field(variantArray, "Element" + field);
72         }
73
74         internal static Type GetStructType(int args) {
75             Debug.Assert(args >= 0);
76             if (args <= 1) return typeof(VariantArray1);
77             if (args <= 2) return typeof(VariantArray2);
78             if (args <= 4) return typeof(VariantArray4);
79             if (args <= 8) return typeof(VariantArray8);
80
81             int size = 1;
82             while (args > size) {
83                 size *= 2;
84             }
85
86             lock (_generatedTypes) {
87                 // See if we can find an existing type
88                 foreach (Type t in _generatedTypes) {
89                     int arity = int.Parse(t.Name.Substring("VariantArray".Length), CultureInfo.InvariantCulture);
90                     if (size == arity) {
91                         return t;
92                     }
93                 }
94
95                 // Else generate a new type
96                 Type type = CreateCustomType(size).MakeGenericType(new Type[]{typeof(Variant)});
97                 _generatedTypes.Add(type);
98                 return type;
99             }
100         }
101
102         private static Type CreateCustomType(int size) {
103             var attrs = TypeAttributes.NotPublic | TypeAttributes.SequentialLayout;
104             TypeBuilder type = UnsafeMethods.DynamicModule.DefineType("VariantArray" + size, attrs, typeof(ValueType));
105             var T = type.DefineGenericParameters(new string[] { "T" })[0];
106             for (int i = 0; i < size; i++) {
107                 type.DefineField("Element" + i, T, FieldAttributes.Public);
108             }
109             return type.CreateType();
110         }
111     }
112 }
113
114 #endif