2 // support.cs: Support routines to work around the fact that System.Reflection.Emit
3 // can not introspect types that are being constructed
6 // Miguel de Icaza (miguel@ximian.com)
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
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);
24 bool HasParams { get; }
25 string ParameterName (int pos);
26 string ParameterDesc (int pos);
27 Parameter.Modifier ParameterModifier (int pos);
28 string GetSignatureForError ();
31 public class ReflectionParameters : ParameterData {
33 bool last_arg_is_params = false;
34 bool is_varargs = false;
36 public ReflectionParameters (MethodBase mb)
40 ParameterInfo [] pi = mb.GetParameters ();
41 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
44 int count = pi.Length-1;
47 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
52 if (attrs.Length == 0)
55 last_arg_is_params = true;
59 public string GetSignatureForError ()
61 StringBuilder sb = new StringBuilder ("(");
62 for (int i = 0; i < pi.Length; ++i) {
65 sb.Append (ParameterDesc (i));
68 return sb.ToString ();
71 public Type ParameterType (int pos)
73 if (last_arg_is_params && pos >= pi.Length - 1)
74 return pi [pi.Length - 1].ParameterType;
75 else if (is_varargs && pos >= pi.Length)
76 return TypeManager.runtime_argument_handle_type;
78 Type t = pi [pos].ParameterType;
84 public string ParameterName (int pos)
86 if (last_arg_is_params && pos >= pi.Length - 1)
87 return pi [pi.Length - 1].Name;
88 else if (is_varargs && pos >= pi.Length)
94 public string ParameterDesc (int pos)
96 if (is_varargs && pos >= pi.Length)
99 StringBuilder sb = new StringBuilder ();
104 Type partype = ParameterType (pos);
105 if (partype.IsByRef){
106 partype = TypeManager.GetElementType (partype);
113 if (pos >= pi.Length - 1 && last_arg_is_params)
114 sb.Append ("params ");
116 sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
118 return sb.ToString ();
122 public Parameter.Modifier ParameterModifier (int pos)
124 if (last_arg_is_params && pos >= pi.Length - 1)
125 return Parameter.Modifier.PARAMS;
126 else if (is_varargs && pos >= pi.Length)
127 return Parameter.Modifier.ARGLIST;
129 Type t = pi [pos].ParameterType;
131 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
132 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
134 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
137 return Parameter.Modifier.NONE;
142 return is_varargs ? pi.Length + 1 : pi.Length;
146 public bool HasParams {
148 return this.last_arg_is_params;
154 public class InternalParameters : ParameterData {
159 public readonly Parameters Parameters;
161 public InternalParameters (Type [] param_types, Parameters parameters)
163 this.param_types = param_types;
164 this.Parameters = parameters;
166 has_varargs = parameters.HasArglist;
168 if (param_types == null)
171 count = param_types.Length;
176 return has_varargs ? count + 1 : count;
180 public bool HasParams {
182 return Parameters.ArrayParameter != null;
186 Parameter GetParameter (int pos)
188 Parameter [] fixed_pars = Parameters.FixedParameters;
189 if (fixed_pars != null){
190 int len = fixed_pars.Length;
192 return Parameters.FixedParameters [pos];
195 return Parameters.ArrayParameter;
198 public string GetSignatureForError ()
200 StringBuilder sb = new StringBuilder ("(");
201 for (int i = 0; i < count; ++i) {
204 sb.Append (ParameterDesc (i));
207 return sb.ToString ();
210 public Type ParameterType (int pos)
212 if (has_varargs && pos >= count)
213 return TypeManager.runtime_argument_handle_type;
215 if (param_types == null)
218 return GetParameter (pos).ExternalType ();
222 public string ParameterName (int pos)
224 if (has_varargs && pos >= count)
227 return GetParameter (pos).Name;
230 public string ParameterDesc (int pos)
232 if (has_varargs && pos >= count)
235 Type t = ParameterType (pos);
236 return (ModifierDesc (pos) + " " + TypeManager.CSharpName (t).Replace ("&", "")).TrimStart ();
239 public string ModifierDesc (int pos)
241 Parameter p = GetParameter (pos);
244 // We need to and for REF/OUT, because if either is set the
245 // extra flag ISBYREF will be set as well
247 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
249 if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
251 if (p.ModFlags == Parameter.Modifier.PARAMS)
257 public Parameter.Modifier ParameterModifier (int pos)
259 if (has_varargs && pos >= count)
260 return Parameter.Modifier.ARGLIST;
262 Parameter.Modifier mod = GetParameter (pos).ModFlags;
264 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
265 mod |= Parameter.Modifier.ISBYREF;
272 class PtrHashtable : Hashtable {
273 sealed class PtrComparer : IComparer {
274 private PtrComparer () {}
276 public static PtrComparer Instance = new PtrComparer ();
278 public int Compare (object x, object y)
287 public PtrHashtable ()
289 comparer = PtrComparer.Instance;
294 * Hashtable whose keys are character arrays with the same length
296 class CharArrayHashtable : Hashtable {
297 sealed class ArrComparer : IComparer {
300 public ArrComparer (int len) {
304 public int Compare (object x, object y)
306 char[] a = (char[])x;
307 char[] b = (char[])y;
309 for (int i = 0; i < len; ++i)
318 protected override int GetHash (Object key)
320 char[] arr = (char[])key;
323 for (int i = 0; i < len; ++i)
324 h = (h << 5) - h + arr [i];
329 public CharArrayHashtable (int len)
332 comparer = new ArrComparer (len);
338 public object Second;
340 public Pair (object f, object s)
348 /// This is a wrapper around StreamReader which is seekable.
350 public class SeekableStreamReader
352 public SeekableStreamReader (StreamReader reader)
354 this.reader = reader;
355 this.buffer = new char [DefaultCacheSize];
357 // Compute the preamble size
359 // Let the StreamWriter autodetect the encoder
362 Encoding enc = reader.CurrentEncoding;
363 preamble_size = (int) reader.BaseStream.Position;
366 public SeekableStreamReader (Stream stream, Encoding encoding)
367 : this (new StreamReader (stream, encoding, true))
372 private const int DefaultCacheSize = 1024;
375 int buffer_start; // in bytes
376 int buffer_size; // in bytes
377 int char_count; // count buffer[] valid characters
378 int pos; // index into buffer[]
382 /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
383 // always reports the correct position and if it's modified, it also takes care of the buffered data.
385 public int Position {
387 return buffer_start + reader.CurrentEncoding.GetByteCount (buffer, 0, pos);
391 // This one is easy: we're modifying the position within our current
393 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
394 int byte_offset = value - buffer_start;
396 // If we have an uni-byte encoding, 'pos' will be the same as
397 // 'byte_offset'. If we have a multi-byte encoding, 'byte_offset'
398 // can be bigger than the desired value of 'pos', but not smaller.
399 // (IOW, the number of characters <= number of bytes)
401 // So, we start pos off at byte_offset, and fix it up.
403 if (pos > char_count)
405 while (reader.CurrentEncoding.GetByteCount (buffer, 0, pos) > byte_offset)
410 if (value == 0) // Skip preamble
411 value = preamble_size;
413 // Ok, now we need to seek.
414 reader.DiscardBufferedData ();
415 reader.BaseStream.Position = buffer_start = value;
416 char_count = buffer_size = pos = 0;
420 private bool ReadBuffer ()
423 buffer_start += buffer_size;
424 char_count = reader.Read (buffer, 0, buffer.Length);
425 buffer_size = reader.CurrentEncoding.GetByteCount (buffer, 0, char_count);
426 return buffer_size > 0;
431 if ((pos >= char_count) && !ReadBuffer ())
439 if ((pos >= char_count) && !ReadBuffer ())
442 return buffer [pos++];
446 public class DoubleHash {
447 const int DEFAULT_INITIAL_BUCKETS = 100;
449 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
451 public DoubleHash (int size)
454 buckets = new Entry [size];
468 public Entry (object key1, object key2, int hash, object value, Entry next)
478 public bool Lookup (object a, object b, out object res)
480 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
482 for (Entry e = buckets [h % count]; e != null; e = e.next) {
483 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
492 public void Insert (object a, object b, object value)
494 // Is it an existing one?
496 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
498 for (Entry e = buckets [h % count]; e != null; e = e.next) {
499 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
503 int bucket = h % count;
504 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
506 // Grow whenever we double in size
507 if (size++ == count) {
511 Entry [] newBuckets = new Entry [count];
512 foreach (Entry root in buckets) {
515 int newLoc = e.hash % count;
517 e.next = newBuckets [newLoc];
518 newBuckets [newLoc] = e;
523 buckets = newBuckets;