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 string ParameterName (int pos);
25 string ParameterDesc (int pos);
26 Parameter.Modifier ParameterModifier (int pos);
29 public class ReflectionParameters : ParameterData {
31 bool last_arg_is_params = false;
32 bool is_varargs = false;
34 public ReflectionParameters (MethodBase mb)
38 ParameterInfo [] pi = mb.GetParameters ();
39 is_varargs = mb.CallingConvention == CallingConventions.VarArgs;
42 int count = pi.Length-1;
45 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
50 if (attrs.Length == 0)
53 last_arg_is_params = true;
57 public Type ParameterType (int pos)
59 if (last_arg_is_params && pos >= pi.Length - 1)
60 return pi [pi.Length - 1].ParameterType;
61 else if (is_varargs && pos >= pi.Length)
62 return TypeManager.runtime_argument_handle_type;
64 Type t = pi [pos].ParameterType;
70 public string ParameterName (int pos)
72 if (last_arg_is_params && pos >= pi.Length - 1)
73 return pi [pi.Length - 1].Name;
74 else if (is_varargs && pos >= pi.Length)
80 public string ParameterDesc (int pos)
82 if (is_varargs && pos >= pi.Length)
85 StringBuilder sb = new StringBuilder ();
90 Type partype = ParameterType (pos);
92 partype = TypeManager.GetElementType (partype);
99 if (pos >= pi.Length - 1 && last_arg_is_params)
100 sb.Append ("params ");
102 sb.Append (TypeManager.CSharpName (partype));
104 return sb.ToString ();
108 public Parameter.Modifier ParameterModifier (int pos)
112 if (last_arg_is_params && pos >= pi.Length - 1)
113 return Parameter.Modifier.PARAMS;
114 else if (is_varargs && pos >= pi.Length)
115 return Parameter.Modifier.ARGLIST;
117 Type t = pi [pos].ParameterType;
119 if ((pi [pos].Attributes & ParameterAttributes.Out) != 0)
120 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
122 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
125 return Parameter.Modifier.NONE;
130 return is_varargs ? pi.Length + 1 : pi.Length;
136 public class InternalParameters : ParameterData {
141 public readonly Parameters Parameters;
143 public InternalParameters (Type [] param_types, Parameters parameters)
145 this.param_types = param_types;
146 this.Parameters = parameters;
149 public InternalParameters (DeclSpace ds, Parameters parameters)
150 : this (parameters.GetParameterInfo (ds), parameters)
152 has_varargs = parameters.HasArglist;
154 if (param_types == null)
157 count = param_types.Length;
162 return has_varargs ? count + 1 : count;
166 Parameter GetParameter (int pos)
168 Parameter [] fixed_pars = Parameters.FixedParameters;
169 if (fixed_pars != null){
170 int len = fixed_pars.Length;
172 return Parameters.FixedParameters [pos];
175 return Parameters.ArrayParameter;
178 public Type ParameterType (int pos)
180 if (has_varargs && pos >= count)
181 return TypeManager.runtime_argument_handle_type;
183 if (param_types == null)
186 return GetParameter (pos).ExternalType ();
190 public string ParameterName (int pos)
192 if (has_varargs && pos >= count)
195 return GetParameter (pos).Name;
198 public string ParameterDesc (int pos)
200 if (has_varargs && pos >= count)
203 string tmp = String.Empty;
204 Parameter p = GetParameter (pos);
207 // We need to and for REF/OUT, because if either is set the
208 // extra flag ISBYREF will be set as well
210 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
212 else if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
214 else if (p.ModFlags == Parameter.Modifier.PARAMS)
217 Type t = ParameterType (pos);
219 return tmp + TypeManager.CSharpName (t);
222 public Parameter.Modifier ParameterModifier (int pos)
224 if (has_varargs && pos >= count)
225 return Parameter.Modifier.ARGLIST;
227 Parameter.Modifier mod = GetParameter (pos).ModFlags;
229 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
230 mod |= Parameter.Modifier.ISBYREF;
237 class PtrHashtable : Hashtable {
238 sealed class PtrComparer : IComparer {
239 private PtrComparer () {}
241 public static PtrComparer Instance = new PtrComparer ();
243 public int Compare (object x, object y)
252 public PtrHashtable ()
254 comparer = PtrComparer.Instance;
259 * Hashtable whose keys are character arrays with the same length
261 class CharArrayHashtable : Hashtable {
262 sealed class ArrComparer : IComparer {
265 public ArrComparer (int len) {
269 public int Compare (object x, object y)
271 char[] a = (char[])x;
272 char[] b = (char[])y;
274 for (int i = 0; i < len; ++i)
283 protected override int GetHash (Object key)
285 char[] arr = (char[])key;
288 for (int i = 0; i < len; ++i)
289 h = (h << 5) - h + arr [i];
294 public CharArrayHashtable (int len)
297 comparer = new ArrComparer (len);
302 // Compares member infos based on their name and
303 // also allows one argument to be a string
305 class MemberInfoCompare : IComparer {
307 public int Compare (object a, object b)
309 if (a == null || b == null){
310 Console.WriteLine ("Invalid information passed");
311 throw new Exception ();
315 return String.Compare ((string) a, ((MemberInfo)b).Name, false, CultureInfo.InvariantCulture);
318 return String.Compare (((MemberInfo)a).Name, (string) b, false, CultureInfo.InvariantCulture);
320 return String.Compare (((MemberInfo)a).Name, ((MemberInfo)b).Name, false, CultureInfo.InvariantCulture);
326 public object Second;
328 public Pair (object f, object s)
336 /// This is a wrapper around StreamReader which is seekable.
338 public class SeekableStreamReader
340 public SeekableStreamReader (StreamReader reader)
342 this.reader = reader;
343 this.buffer = new char [DefaultCacheSize];
345 // Compute the preamble size
347 // Let the StreamWriter autodetect the encoder
350 reader.BaseStream.Position = 0;
351 Encoding enc = reader.CurrentEncoding;
352 // First of all, get at least a char
354 byte[] auxb = new byte [50];
359 br = reader.BaseStream.Read (auxb, num_bytes, auxb.Length - num_bytes);
361 num_chars = enc.GetCharCount (auxb, 0, num_bytes);
363 while (num_chars == 0 && br > 0);
367 // Now, check which bytes at the beginning have no effect in the
371 while (enc.GetCharCount (auxb, p, num_bytes-p) >= num_chars)
374 preamble_size = p - 1;
375 reader.BaseStream.Position = 0;
376 reader.DiscardBufferedData ();
378 buffer_start = preamble_size;
382 public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)
383 : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks))
388 private const int DefaultCacheSize = 1024;
391 int buffer_start; // in bytes
392 int buffer_size; // in bytes
393 int char_count; // count buffer[] valid characters
394 int pos; // index into buffer[]
398 /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
399 // always reports the correct position and if it's modified, it also takes care of the buffered data.
401 public int Position {
403 return buffer_start + reader.CurrentEncoding.GetByteCount (buffer, 0, pos);
407 // This one is easy: we're modifying the position within our current
409 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
410 int byte_offset = value - buffer_start;
412 // encoded characters can take more than 1 byte length
413 while (reader.CurrentEncoding.GetByteCount (buffer, 0, pos) > byte_offset)
419 if (value == 0) // Skip preamble
420 value = preamble_size;
422 // Ok, now we need to seek.
423 reader.DiscardBufferedData ();
424 reader.BaseStream.Position = buffer_start = value;
425 char_count = buffer_size = pos = 0;
429 private bool ReadBuffer ()
432 buffer_start += buffer_size;
433 char_count = reader.Read (buffer, 0, buffer.Length);
434 buffer_size = reader.CurrentEncoding.GetByteCount (buffer, 0, char_count);
435 return buffer_size > 0;
440 if ((pos >= char_count) && !ReadBuffer ())
448 if ((pos >= char_count) && !ReadBuffer ())
451 return buffer [pos++];
455 public class DoubleHash {
456 const int DEFAULT_INITIAL_BUCKETS = 100;
458 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
460 public DoubleHash (int size)
463 buckets = new Entry [size];
477 public Entry (object key1, object key2, int hash, object value, Entry next)
487 public bool Lookup (object a, object b, out object res)
489 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
491 for (Entry e = buckets [h % count]; e != null; e = e.next) {
492 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
501 public void Insert (object a, object b, object value)
503 // Is it an existing one?
505 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
507 for (Entry e = buckets [h % count]; e != null; e = e.next) {
508 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
512 int bucket = h % count;
513 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
515 // Grow whenever we double in size
516 if (size++ == count) {
520 Entry [] newBuckets = new Entry [count];
521 foreach (Entry root in buckets) {
524 int newLoc = e.hash % count;
526 e.next = newBuckets [newLoc];
527 newBuckets [newLoc] = e;
532 buckets = newBuckets;