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);
31 public class ReflectionParameters : ParameterData {
34 bool last_arg_is_params = false;
35 bool is_varargs = false;
38 public ReflectionParameters (MethodBase mb)
42 ParameterInfo [] pi = mb.GetParameters ();
43 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
46 int count = pi.Length-1;
51 if (mb.Mono_IsInflatedMethod) {
52 MethodInfo generic = mb.GetGenericMethodDefinition ();
53 gpd = TypeManager.GetParameterData (generic);
55 last_arg_is_params = gpd.HasParams;
59 if (mb.IsGenericMethodDefinition)
60 type_params = mb.GetGenericArguments ();
62 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
66 if (attrs.Length == 0)
69 last_arg_is_params = true;
72 public Type ParameterType (int pos)
74 if (last_arg_is_params && pos >= pi.Length - 1)
75 return pi [pi.Length - 1].ParameterType;
76 else if (is_varargs && pos >= pi.Length)
77 return TypeManager.runtime_argument_handle_type;
79 Type t = pi [pos].ParameterType;
85 public GenericConstraints GenericConstraints (int pos)
88 return gpd.GenericConstraints (pos);
90 if (type_params == null)
93 return new ReflectionConstraints (type_params [pos]);
96 public string ParameterName (int pos)
99 return gpd.ParameterName (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)
106 return pi [pos].Name;
109 public string ParameterDesc (int pos)
111 if (is_varargs && pos >= pi.Length)
114 StringBuilder sb = new StringBuilder ();
119 Type partype = ParameterType (pos);
120 if (partype.IsByRef){
121 partype = TypeManager.GetElementType (partype);
128 if (pos >= pi.Length - 1 && last_arg_is_params)
129 sb.Append ("params ");
131 sb.Append (TypeManager.CSharpName (partype));
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;
145 return gpd.ParameterModifier (pos);
147 Type t = pi [pos].ParameterType;
149 if ((pi [pos].Attributes & ParameterAttributes.Out) != 0)
150 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
152 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
155 return Parameter.Modifier.NONE;
160 return is_varargs ? pi.Length + 1 : pi.Length;
164 public bool HasParams {
166 return this.last_arg_is_params;
171 public class InternalParameters : ParameterData {
176 public readonly Parameters Parameters;
177 public readonly TypeParameter[] TypeParameters;
179 public InternalParameters (Type [] param_types, Parameters parameters)
181 this.param_types = param_types;
182 this.Parameters = parameters;
184 has_varargs = parameters.HasArglist;
186 if (param_types == null)
189 count = param_types.Length;
192 public InternalParameters (Type [] param_types, Parameters parameters,
193 TypeParameter [] type_params)
194 : this (param_types, parameters)
196 this.TypeParameters = type_params;
201 return has_varargs ? count + 1 : count;
205 public bool HasParams {
207 return Parameters.ArrayParameter != null;
211 Parameter GetParameter (int pos)
213 Parameter [] fixed_pars = Parameters.FixedParameters;
214 if (fixed_pars != null){
215 int len = fixed_pars.Length;
217 return Parameters.FixedParameters [pos];
220 return Parameters.ArrayParameter;
223 public Type ParameterType (int pos)
225 if (has_varargs && pos >= count)
226 return TypeManager.runtime_argument_handle_type;
228 if (param_types == null)
231 return GetParameter (pos).ExternalType ();
234 public GenericConstraints GenericConstraints (int pos)
236 if (TypeParameters == null)
239 return TypeParameters [pos].Constraints;
242 public string ParameterName (int pos)
244 if (has_varargs && pos >= count)
247 return GetParameter (pos).Name;
250 public string ParameterDesc (int pos)
252 if (has_varargs && pos >= count)
255 Type t = ParameterType (pos);
256 return ModifierDesc (pos) + " " + TypeManager.CSharpName (t);
259 public string ModifierDesc (int pos)
261 Parameter p = GetParameter (pos);
264 // We need to and for REF/OUT, because if either is set the
265 // extra flag ISBYREF will be set as well
267 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
269 if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
271 if (p.ModFlags == Parameter.Modifier.PARAMS)
277 public Parameter.Modifier ParameterModifier (int pos)
279 if (has_varargs && pos >= count)
280 return Parameter.Modifier.ARGLIST;
282 Parameter.Modifier mod = GetParameter (pos).ModFlags;
284 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
285 mod |= Parameter.Modifier.ISBYREF;
292 public class ReflectionConstraints : GenericConstraints
294 GenericParameterAttributes attrs;
296 Type class_constraint;
297 Type[] iface_constraints;
299 public ReflectionConstraints (Type t)
301 Type[] constraints = t.GetGenericParameterConstraints ();
302 if ((constraints.Length > 0) && !constraints [0].IsInterface) {
303 class_constraint = constraints [0];
304 iface_constraints = new Type [constraints.Length - 1];
305 Array.Copy (constraints, 1, iface_constraints, 0, constraints.Length - 1);
307 iface_constraints = constraints;
308 attrs = t.GenericParameterAttributes;
310 if (HasValueTypeConstraint)
311 base_type = TypeManager.value_type;
312 else if (class_constraint != null)
313 base_type = class_constraint;
315 base_type = TypeManager.object_type;
318 public override GenericParameterAttributes Attributes {
319 get { return attrs; }
322 public override Type ClassConstraint {
323 get { return class_constraint; }
326 public override Type EffectiveBaseClass {
327 get { return base_type; }
330 public override Type[] InterfaceConstraints {
331 get { return iface_constraints; }
335 class PtrHashtable : Hashtable {
336 sealed class PtrComparer : IComparer {
337 private PtrComparer () {}
339 public static PtrComparer Instance = new PtrComparer ();
341 public int Compare (object x, object y)
350 public PtrHashtable ()
352 comparer = PtrComparer.Instance;
357 * Hashtable whose keys are character arrays with the same length
359 class CharArrayHashtable : Hashtable {
360 sealed class ArrComparer : IComparer {
363 public ArrComparer (int len) {
367 public int Compare (object x, object y)
369 char[] a = (char[])x;
370 char[] b = (char[])y;
372 for (int i = 0; i < len; ++i)
381 protected override int GetHash (Object key)
383 char[] arr = (char[])key;
386 for (int i = 0; i < len; ++i)
387 h = (h << 5) - h + arr [i];
392 public CharArrayHashtable (int len)
395 comparer = new ArrComparer (len);
401 public object Second;
403 public Pair (object f, object s)
411 /// This is a wrapper around StreamReader which is seekable.
413 public class SeekableStreamReader
415 public SeekableStreamReader (StreamReader reader)
417 this.reader = reader;
418 this.buffer = new char [DefaultCacheSize];
420 // Compute the preamble size
422 // Let the StreamWriter autodetect the encoder
425 reader.BaseStream.Position = 0;
426 Encoding enc = reader.CurrentEncoding;
427 // First of all, get at least a char
429 byte[] auxb = new byte [50];
434 br = reader.BaseStream.Read (auxb, num_bytes, auxb.Length - num_bytes);
436 num_chars = enc.GetCharCount (auxb, 0, num_bytes);
438 while (num_chars == 0 && br > 0);
442 // Now, check which bytes at the beginning have no effect in the
446 while (enc.GetCharCount (auxb, p, num_bytes-p) >= num_chars)
449 preamble_size = p - 1;
450 reader.BaseStream.Position = 0;
451 reader.DiscardBufferedData ();
453 buffer_start = preamble_size;
457 public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)
458 : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks))
463 private const int DefaultCacheSize = 1024;
466 int buffer_start; // in bytes
467 int buffer_size; // in bytes
468 int char_count; // count buffer[] valid characters
469 int pos; // index into buffer[]
473 /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
474 // always reports the correct position and if it's modified, it also takes care of the buffered data.
476 public int Position {
478 return buffer_start + reader.CurrentEncoding.GetByteCount (buffer, 0, pos);
482 // This one is easy: we're modifying the position within our current
484 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
485 int byte_offset = value - buffer_start;
487 // pos is an index into a char
488 // buffer so it might be
489 // greater than the buffer
490 // length now, if the buffer
491 // contains multibyte chars
494 // encoded characters can take
495 // more than 1 byte length.
496 while ((pos > buffer.Length) ||
497 reader.CurrentEncoding.GetByteCount (buffer, 0, pos) > byte_offset) {
504 if (value == 0) // Skip preamble
505 value = preamble_size;
507 // Ok, now we need to seek.
508 reader.DiscardBufferedData ();
509 reader.BaseStream.Position = buffer_start = value;
510 char_count = buffer_size = pos = 0;
514 private bool ReadBuffer ()
517 buffer_start += buffer_size;
518 char_count = reader.Read (buffer, 0, buffer.Length);
519 buffer_size = reader.CurrentEncoding.GetByteCount (buffer, 0, char_count);
520 return buffer_size > 0;
525 if ((pos >= char_count) && !ReadBuffer ())
533 if ((pos >= char_count) && !ReadBuffer ())
536 return buffer [pos++];
540 public class DoubleHash {
541 const int DEFAULT_INITIAL_BUCKETS = 100;
543 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
545 public DoubleHash (int size)
548 buckets = new Entry [size];
562 public Entry (object key1, object key2, int hash, object value, Entry next)
572 public bool Lookup (object a, object b, out object res)
574 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
576 for (Entry e = buckets [h % count]; e != null; e = e.next) {
577 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
586 public void Insert (object a, object b, object value)
588 // Is it an existing one?
590 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
592 for (Entry e = buckets [h % count]; e != null; e = e.next) {
593 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
597 int bucket = h % count;
598 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
600 // Grow whenever we double in size
601 if (size++ == count) {
605 Entry [] newBuckets = new Entry [count];
606 foreach (Entry root in buckets) {
609 int newLoc = e.hash % count;
611 e.next = newBuckets [newLoc];
612 newBuckets [newLoc] = e;
617 buckets = newBuckets;