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);
23 GenericConstraints GenericConstraints (int pos);
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 {
35 bool last_arg_is_params = false;
36 bool is_varargs = false;
39 public ReflectionParameters (MethodBase mb)
43 ParameterInfo [] pi = mb.GetParameters ();
44 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
47 int count = pi.Length-1;
52 if (mb.Mono_IsInflatedMethod) {
53 MethodInfo generic = mb.GetGenericMethodDefinition ();
54 gpd = TypeManager.GetParameterData (generic);
56 last_arg_is_params = gpd.HasParams;
60 if (mb.IsGenericMethodDefinition)
61 type_params = mb.GetGenericArguments ();
63 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
67 if (attrs.Length == 0)
70 last_arg_is_params = true;
73 public string GetSignatureForError ()
75 StringBuilder sb = new StringBuilder ("(");
76 for (int i = 0; i < pi.Length; ++i) {
79 sb.Append (ParameterDesc (i));
82 return sb.ToString ();
85 public Type ParameterType (int pos)
87 if (last_arg_is_params && pos >= pi.Length - 1)
88 return pi [pi.Length - 1].ParameterType;
89 else if (is_varargs && pos >= pi.Length)
90 return TypeManager.runtime_argument_handle_type;
92 Type t = pi [pos].ParameterType;
98 public GenericConstraints GenericConstraints (int pos)
101 return gpd.GenericConstraints (pos);
103 if (type_params == null)
106 return new ReflectionConstraints (type_params [pos]);
109 public string ParameterName (int pos)
112 return gpd.ParameterName (pos);
114 if (last_arg_is_params && pos >= pi.Length - 1)
115 return pi [pi.Length - 1].Name;
116 else if (is_varargs && pos >= pi.Length)
119 return pi [pos].Name;
122 public string ParameterDesc (int pos)
124 if (is_varargs && pos >= pi.Length)
127 StringBuilder sb = new StringBuilder ();
132 Type partype = ParameterType (pos);
133 if (partype.IsByRef){
134 partype = TypeManager.GetElementType (partype);
141 if (pos >= pi.Length - 1 && last_arg_is_params)
142 sb.Append ("params ");
144 sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
146 return sb.ToString ();
150 public Parameter.Modifier ParameterModifier (int pos)
152 if (last_arg_is_params && pos >= pi.Length - 1)
153 return Parameter.Modifier.PARAMS;
154 else if (is_varargs && pos >= pi.Length)
155 return Parameter.Modifier.ARGLIST;
158 return gpd.ParameterModifier (pos);
160 Type t = pi [pos].ParameterType;
162 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
163 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
165 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
168 return Parameter.Modifier.NONE;
173 return is_varargs ? pi.Length + 1 : pi.Length;
177 public bool HasParams {
179 return this.last_arg_is_params;
184 public class InternalParameters : ParameterData {
189 public readonly Parameters Parameters;
190 public readonly TypeParameter[] TypeParameters;
192 public InternalParameters (Type [] param_types, Parameters parameters)
194 this.param_types = param_types;
195 this.Parameters = parameters;
197 has_varargs = parameters.HasArglist;
199 if (param_types == null)
202 count = param_types.Length;
205 public InternalParameters (Type [] param_types, Parameters parameters,
206 TypeParameter [] type_params)
207 : this (param_types, parameters)
209 this.TypeParameters = type_params;
214 return has_varargs ? count + 1 : count;
218 public bool HasParams {
220 return Parameters.ArrayParameter != null;
224 Parameter GetParameter (int pos)
226 Parameter [] fixed_pars = Parameters.FixedParameters;
227 if (fixed_pars != null){
228 int len = fixed_pars.Length;
230 return Parameters.FixedParameters [pos];
233 return Parameters.ArrayParameter;
236 public string GetSignatureForError ()
238 StringBuilder sb = new StringBuilder ("(");
239 for (int i = 0; i < count; ++i) {
242 sb.Append (ParameterDesc (i));
245 return sb.ToString ();
248 public Type ParameterType (int pos)
250 if (has_varargs && pos >= count)
251 return TypeManager.runtime_argument_handle_type;
253 if (param_types == null)
256 return GetParameter (pos).ExternalType ();
259 public GenericConstraints GenericConstraints (int pos)
261 if (TypeParameters == null)
264 return TypeParameters [pos].Constraints;
267 public string ParameterName (int pos)
269 if (has_varargs && pos >= count)
272 return GetParameter (pos).Name;
275 public string ParameterDesc (int pos)
277 if (has_varargs && pos >= count)
280 Type t = ParameterType (pos);
281 return (ModifierDesc (pos) + " " + TypeManager.CSharpName (t).Replace ("&", "")).TrimStart ();
284 public string ModifierDesc (int pos)
286 Parameter p = GetParameter (pos);
289 // We need to and for REF/OUT, because if either is set the
290 // extra flag ISBYREF will be set as well
292 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
294 if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
296 if (p.ModFlags == Parameter.Modifier.PARAMS)
302 public Parameter.Modifier ParameterModifier (int pos)
304 if (has_varargs && pos >= count)
305 return Parameter.Modifier.ARGLIST;
307 Parameter.Modifier mod = GetParameter (pos).ModFlags;
309 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
310 mod |= Parameter.Modifier.ISBYREF;
317 public class ReflectionConstraints : GenericConstraints
319 GenericParameterAttributes attrs;
321 Type class_constraint;
322 Type[] iface_constraints;
324 public ReflectionConstraints (Type t)
326 Type[] constraints = t.GetGenericParameterConstraints ();
327 if ((constraints.Length > 0) && !constraints [0].IsInterface) {
328 class_constraint = constraints [0];
329 iface_constraints = new Type [constraints.Length - 1];
330 Array.Copy (constraints, 1, iface_constraints, 0, constraints.Length - 1);
332 iface_constraints = constraints;
333 attrs = t.GenericParameterAttributes;
335 if (HasValueTypeConstraint)
336 base_type = TypeManager.value_type;
337 else if (class_constraint != null)
338 base_type = class_constraint;
340 base_type = TypeManager.object_type;
343 public override GenericParameterAttributes Attributes {
344 get { return attrs; }
347 public override Type ClassConstraint {
348 get { return class_constraint; }
351 public override Type EffectiveBaseClass {
352 get { return base_type; }
355 public override Type[] InterfaceConstraints {
356 get { return iface_constraints; }
360 class PtrHashtable : Hashtable {
361 sealed class PtrComparer : IComparer {
362 private PtrComparer () {}
364 public static PtrComparer Instance = new PtrComparer ();
366 public int Compare (object x, object y)
375 public PtrHashtable ()
377 comparer = PtrComparer.Instance;
382 * Hashtable whose keys are character arrays with the same length
384 class CharArrayHashtable : Hashtable {
385 sealed class ArrComparer : IComparer {
388 public ArrComparer (int len) {
392 public int Compare (object x, object y)
394 char[] a = (char[])x;
395 char[] b = (char[])y;
397 for (int i = 0; i < len; ++i)
406 protected override int GetHash (Object key)
408 char[] arr = (char[])key;
411 for (int i = 0; i < len; ++i)
412 h = (h << 5) - h + arr [i];
417 public CharArrayHashtable (int len)
420 comparer = new ArrComparer (len);
426 public object Second;
428 public Pair (object f, object s)
436 /// This is a wrapper around StreamReader which is seekable.
438 public class SeekableStreamReader
440 public SeekableStreamReader (StreamReader reader)
442 this.reader = reader;
443 this.buffer = new char [DefaultCacheSize];
445 // Compute the preamble size
447 // Let the StreamWriter autodetect the encoder
450 preamble_size = (int) reader.BaseStream.Position;
453 public SeekableStreamReader (Stream stream, Encoding encoding)
454 : this (new StreamReader (stream, encoding, true))
459 private const int DefaultCacheSize = 1024;
462 int buffer_start; // in bytes
463 int buffer_size; // in bytes
464 int char_count; // count buffer[] valid characters
465 int pos; // index into buffer[]
469 /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
470 // always reports the correct position and if it's modified, it also takes care of the buffered data.
472 public int Position {
474 return buffer_start + reader.CurrentEncoding.GetByteCount (buffer, 0, pos);
478 // This one is easy: we're modifying the position within our current
480 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
481 int byte_offset = value - buffer_start;
483 // If we have an uni-byte encoding, 'pos' will be the same as
484 // 'byte_offset'. If we have a multi-byte encoding, 'byte_offset'
485 // can be bigger than the desired value of 'pos', but not smaller.
486 // (IOW, the number of characters <= number of bytes)
488 // So, we start pos off at byte_offset, and fix it up.
490 if (pos > char_count)
492 while (reader.CurrentEncoding.GetByteCount (buffer, 0, pos) > byte_offset)
497 if (value == 0) // Skip preamble
498 value = preamble_size;
500 // Ok, now we need to seek.
501 reader.DiscardBufferedData ();
502 reader.BaseStream.Position = buffer_start = value;
503 char_count = buffer_size = pos = 0;
507 private bool ReadBuffer ()
510 buffer_start += buffer_size;
511 char_count = reader.Read (buffer, 0, buffer.Length);
512 buffer_size = reader.CurrentEncoding.GetByteCount (buffer, 0, char_count);
513 return buffer_size > 0;
518 if ((pos >= char_count) && !ReadBuffer ())
526 if ((pos >= char_count) && !ReadBuffer ())
529 return buffer [pos++];
533 public class DoubleHash {
534 const int DEFAULT_INITIAL_BUCKETS = 100;
536 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
538 public DoubleHash (int size)
541 buckets = new Entry [size];
555 public Entry (object key1, object key2, int hash, object value, Entry next)
565 public bool Lookup (object a, object b, out object res)
567 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
569 for (Entry e = buckets [h % count]; e != null; e = e.next) {
570 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
579 public void Insert (object a, object b, object value)
581 // Is it an existing one?
583 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
585 for (Entry e = buckets [h % count]; e != null; e = e.next) {
586 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
590 int bucket = h % count;
591 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
593 // Grow whenever we double in size
594 if (size++ == count) {
598 Entry [] newBuckets = new Entry [count];
599 foreach (Entry root in buckets) {
602 int newLoc = e.hash % count;
604 e.next = newBuckets [newLoc];
605 newBuckets [newLoc] = e;
610 buckets = newBuckets;