In ilasm/tests:
[mcs.git] / mcs / support.cs
blob5d227bf3f442c5b4f23e894d60a420e0ed9e4ab8
1 //
2 // support.cs: Support routines to work around the fact that System.Reflection.Emit
3 // can not introspect types that are being constructed
4 //
5 // Author:
6 // Miguel de Icaza (miguel@ximian.com)
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
11 using System;
12 using System.IO;
13 using System.Text;
14 using System.Reflection;
15 using System.Collections;
16 using System.Reflection.Emit;
17 using System.Globalization;
19 namespace Mono.CSharp {
21 public interface ParameterData {
22 Type ParameterType (int pos);
23 Type [] Types { get; }
24 int Count { get; }
25 bool HasParams { get; }
26 string ParameterName (int pos);
27 string ParameterDesc (int pos);
28 Parameter.Modifier ParameterModifier (int pos);
29 string GetSignatureForError ();
32 public class ReflectionParameters : ParameterData {
33 ParameterInfo [] pi;
34 Type [] types;
35 bool last_arg_is_params = false;
36 bool is_varargs = false;
38 public ReflectionParameters (MethodBase mb)
40 object [] attrs;
42 ParameterInfo [] pi = mb.GetParameters ();
43 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
45 this.pi = pi;
46 int count = pi.Length-1;
48 if (pi.Length == 0) {
49 types = TypeManager.NoTypes;
50 } else {
51 types = new Type [pi.Length];
52 for (int i = 0; i < pi.Length; i++)
53 types [i] = pi [i].ParameterType;
56 if (count >= 0) {
57 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
59 if (attrs == null)
60 return;
62 if (attrs.Length == 0)
63 return;
65 last_arg_is_params = true;
69 public string GetSignatureForError ()
71 StringBuilder sb = new StringBuilder ("(");
72 for (int i = 0; i < pi.Length; ++i) {
73 if (i != 0)
74 sb.Append (", ");
75 sb.Append (ParameterDesc (i));
77 if (is_varargs) {
78 if (pi.Length > 0)
79 sb.Append (", ");
80 sb.Append ("__arglist");
82 sb.Append (')');
83 return sb.ToString ();
86 public Type ParameterType (int pos)
88 if (last_arg_is_params && pos >= pi.Length - 1)
89 return pi [pi.Length - 1].ParameterType;
90 else if (is_varargs && pos >= pi.Length)
91 return TypeManager.runtime_argument_handle_type;
92 else {
93 Type t = pi [pos].ParameterType;
95 return t;
99 public string ParameterName (int pos)
101 if (last_arg_is_params && pos >= pi.Length - 1)
102 return pi [pi.Length - 1].Name;
103 else if (is_varargs && pos >= pi.Length)
104 return "__arglist";
105 else
106 return pi [pos].Name;
109 public string ParameterDesc (int pos)
111 if (is_varargs && pos >= pi.Length)
112 return "";
114 StringBuilder sb = new StringBuilder ();
116 if (pi [pos].IsIn)
117 sb.Append ("in ");
119 Type partype = ParameterType (pos);
120 if (partype.IsByRef){
121 partype = TypeManager.GetElementType (partype);
122 if (pi [pos].IsOut)
123 sb.Append ("out ");
124 else
125 sb.Append ("ref ");
128 if (pos >= pi.Length - 1 && last_arg_is_params)
129 sb.Append ("params ");
131 sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
133 return sb.ToString ();
137 public Parameter.Modifier ParameterModifier (int pos)
139 if (last_arg_is_params && pos >= pi.Length - 1)
140 return Parameter.Modifier.PARAMS;
141 else if (is_varargs && pos >= pi.Length)
142 return Parameter.Modifier.ARGLIST;
144 Type t = pi [pos].ParameterType;
145 if (t.IsByRef){
146 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
147 return Parameter.Modifier.OUT;
148 else
149 return Parameter.Modifier.REF;
152 return Parameter.Modifier.NONE;
155 public int Count {
156 get {
157 return is_varargs ? pi.Length + 1 : pi.Length;
161 public bool HasParams {
162 get {
163 return this.last_arg_is_params;
167 public Type[] Types {
168 get {
169 return types;
175 class PtrHashtable : Hashtable {
176 sealed class PtrComparer : IComparer {
177 private PtrComparer () {}
179 public static PtrComparer Instance = new PtrComparer ();
181 public int Compare (object x, object y)
183 if (x == y)
184 return 0;
185 else
186 return 1;
190 public PtrHashtable ()
192 comparer = PtrComparer.Instance;
197 * Hashtable whose keys are character arrays with the same length
199 class CharArrayHashtable : Hashtable {
200 sealed class ArrComparer : IComparer {
201 private int len;
203 public ArrComparer (int len) {
204 this.len = len;
207 public int Compare (object x, object y)
209 char[] a = (char[])x;
210 char[] b = (char[])y;
212 for (int i = 0; i < len; ++i)
213 if (a [i] != b [i])
214 return 1;
215 return 0;
219 private int len;
221 protected override int GetHash (Object key)
223 char[] arr = (char[])key;
224 int h = 0;
226 for (int i = 0; i < len; ++i)
227 h = (h << 5) - h + arr [i];
229 return h;
232 public CharArrayHashtable (int len)
234 this.len = len;
235 comparer = new ArrComparer (len);
239 struct Pair {
240 public object First;
241 public object Second;
243 public Pair (object f, object s)
245 First = f;
246 Second = s;
250 /// <summary>
251 /// This is a wrapper around StreamReader which is seekable backwards
252 /// within a window of around 2048 chars.
253 /// </summary>
254 public class SeekableStreamReader
256 public SeekableStreamReader (StreamReader reader)
258 this.reader = reader;
259 this.buffer = new char [AverageReadLength * 3];
261 // Let the StreamWriter autodetect the encoder
262 reader.Peek ();
265 public SeekableStreamReader (Stream stream, Encoding encoding)
266 : this (new StreamReader (stream, encoding, true))
269 StreamReader reader;
271 private const int AverageReadLength = 1024;
273 char[] buffer;
274 int buffer_start; // in chars
275 int char_count; // count buffer[] valid characters
276 int pos; // index into buffer[]
278 /// <remarks>
279 /// This value corresponds to the current position in a stream of characters.
280 /// The StreamReader hides its manipulation of the underlying byte stream and all
281 /// character set/decoding issues. Thus, we cannot use this position to guess at
282 /// the corresponding position in the underlying byte stream even though there is
283 /// a correlation between them.
284 /// </remarks>
285 public int Position {
286 get { return buffer_start + pos; }
288 set {
289 if (value < buffer_start || value > buffer_start + char_count)
290 throw new InternalErrorException ("can't seek that far back: " + (pos - value));
291 pos = value - buffer_start;
295 private bool ReadBuffer ()
297 int slack = buffer.Length - char_count;
298 if (slack <= AverageReadLength / 2) {
299 // shift the buffer to make room for AverageReadLength number of characters
300 int shift = AverageReadLength - slack;
301 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
302 pos -= shift;
303 char_count -= shift;
304 buffer_start += shift;
305 slack += shift; // slack == AverageReadLength
308 int chars_read = reader.Read (buffer, char_count, slack);
309 char_count += chars_read;
311 return pos < char_count;
314 public int Peek ()
316 if ((pos >= char_count) && !ReadBuffer ())
317 return -1;
319 return buffer [pos];
322 public int Read ()
324 if ((pos >= char_count) && !ReadBuffer ())
325 return -1;
327 return buffer [pos++];
331 public class DoubleHash {
332 const int DEFAULT_INITIAL_BUCKETS = 100;
334 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
336 public DoubleHash (int size)
338 count = size;
339 buckets = new Entry [size];
342 int count;
343 Entry [] buckets;
344 int size = 0;
346 class Entry {
347 public object key1;
348 public object key2;
349 public int hash;
350 public object value;
351 public Entry next;
353 public Entry (object key1, object key2, int hash, object value, Entry next)
355 this.key1 = key1;
356 this.key2 = key2;
357 this.hash = hash;
358 this.next = next;
359 this.value = value;
363 public bool Lookup (object a, object b, out object res)
365 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
367 for (Entry e = buckets [h % count]; e != null; e = e.next) {
368 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
369 res = e.value;
370 return true;
373 res = null;
374 return false;
377 public void Insert (object a, object b, object value)
379 // Is it an existing one?
381 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
383 for (Entry e = buckets [h % count]; e != null; e = e.next) {
384 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
385 e.value = value;
388 int bucket = h % count;
389 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
391 // Grow whenever we double in size
392 if (size++ == count) {
393 count <<= 1;
394 count ++;
396 Entry [] newBuckets = new Entry [count];
397 foreach (Entry root in buckets) {
398 Entry e = root;
399 while (e != null) {
400 int newLoc = e.hash % count;
401 Entry n = e.next;
402 e.next = newBuckets [newLoc];
403 newBuckets [newLoc] = e;
404 e = n;
408 buckets = newBuckets;