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 GenericConstraints {
22 bool HasConstructor { get; }
23 bool IsReferenceType { get; }
24 bool IsValueType { get; }
25 bool HasClassConstraint { get; }
26 Type ClassConstraint { get; }
27 Type[] InterfaceConstraints { get; }
30 public interface ParameterData {
31 Type ParameterType (int pos);
32 GenericConstraints GenericConstraints (int pos);
33 bool HasArrayParameter { get; }
35 string ParameterName (int pos);
36 string ParameterDesc (int pos);
37 Parameter.Modifier ParameterModifier (int pos);
40 public class ReflectionParameters : ParameterData {
43 bool last_arg_is_params = false;
44 bool is_varargs = false;
47 public ReflectionParameters (MethodBase mb)
51 ParameterInfo [] pi = mb.GetParameters ();
52 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
55 int count = pi.Length-1;
60 if (mb.Mono_IsInflatedMethod) {
61 MethodInfo generic = mb.GetGenericMethodDefinition ();
62 gpd = Invocation.GetParameterData (generic);
64 last_arg_is_params = gpd.HasArrayParameter;
68 if (mb.IsGenericMethodDefinition)
69 type_params = mb.GetGenericArguments ();
71 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
75 if (attrs.Length == 0)
78 last_arg_is_params = true;
81 public bool HasArrayParameter {
82 get { return last_arg_is_params; }
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 ReflectionConstraints.Create (type_params [pos]);
109 public string ParameterName (int pos)
111 if (last_arg_is_params && pos >= pi.Length - 1)
112 return pi [pi.Length - 1].Name;
113 else if (is_varargs && pos >= pi.Length)
116 return pi [pos].Name;
119 public string ParameterDesc (int pos)
121 if (is_varargs && pos >= pi.Length)
124 StringBuilder sb = new StringBuilder ();
129 Type partype = ParameterType (pos);
130 if (partype.IsByRef){
131 partype = TypeManager.GetElementType (partype);
138 if (pos >= pi.Length - 1 && last_arg_is_params)
139 sb.Append ("params ");
141 sb.Append (TypeManager.CSharpName (partype));
143 return sb.ToString ();
147 public Parameter.Modifier ParameterModifier (int pos)
151 if (last_arg_is_params && pos >= pi.Length - 1)
152 return Parameter.Modifier.PARAMS;
153 else if (is_varargs && pos >= pi.Length)
154 return Parameter.Modifier.ARGLIST;
156 Type t = pi [pos].ParameterType;
158 if ((pi [pos].Attributes & ParameterAttributes.Out) != 0)
159 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
161 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
164 return Parameter.Modifier.NONE;
169 return is_varargs ? pi.Length + 1 : pi.Length;
173 protected class ReflectionConstraints : GenericConstraints
176 bool is_reference_type;
178 Type class_constraint;
179 Type[] iface_constraints;
181 protected ReflectionConstraints (bool has_ctor, Type class_constr,
182 Type[] iface_constrs)
184 this.has_ctor = has_ctor;
185 this.class_constraint = class_constr;
186 this.iface_constraints = iface_constrs;
188 if (class_constraint != null) {
189 if (class_constraint == TypeManager.object_type)
190 is_reference_type = true;
191 else if (class_constraint == TypeManager.value_type)
192 is_value_type = true;
196 public static GenericConstraints Create (Type t)
198 Type class_constr = null;
199 Type[] iface_constrs = t.GetInterfaces ();
200 if (iface_constrs == null)
201 iface_constrs = Type.EmptyTypes;
202 if (t.BaseType != TypeManager.object_type)
203 class_constr = t.BaseType;
205 return new ReflectionConstraints (
206 false, class_constr, iface_constrs);
209 public bool HasConstructor {
210 get { return has_ctor; }
213 public bool HasClassConstraint {
214 get { return class_constraint != null; }
217 public bool IsReferenceType {
218 get { return is_reference_type; }
221 public bool IsValueType {
222 get { return is_value_type; }
225 public Type ClassConstraint {
226 get { return class_constraint; }
229 public Type[] InterfaceConstraints {
230 get { return iface_constraints; }
235 public class InternalParameters : ParameterData {
240 public readonly Parameters Parameters;
241 public readonly TypeParameter[] TypeParameters;
243 public InternalParameters (Type [] param_types, Parameters parameters)
245 this.param_types = param_types;
246 this.Parameters = parameters;
249 public InternalParameters (DeclSpace ds, Parameters parameters)
250 : this (parameters.GetParameterInfo (ds), parameters)
252 has_varargs = parameters.HasArglist;
254 if (param_types == null)
257 count = param_types.Length;
260 public InternalParameters (DeclSpace ds, Parameters parameters,
261 TypeParameter [] type_params)
262 : this (ds, parameters)
264 this.TypeParameters = type_params;
269 return has_varargs ? count + 1 : count;
273 public bool HasArrayParameter {
274 get { return Parameters.ArrayParameter != null; }
277 Parameter GetParameter (int pos)
279 Parameter [] fixed_pars = Parameters.FixedParameters;
280 if (fixed_pars != null){
281 int len = fixed_pars.Length;
283 return Parameters.FixedParameters [pos];
286 return Parameters.ArrayParameter;
289 public Type ParameterType (int pos)
291 if (has_varargs && pos >= count)
292 return TypeManager.runtime_argument_handle_type;
294 if (param_types == null)
297 return GetParameter (pos).ExternalType ();
300 public GenericConstraints GenericConstraints (int pos)
302 if (TypeParameters == null)
305 return TypeParameters [pos].Constraints;
308 public string ParameterName (int pos)
310 if (has_varargs && pos >= count)
313 return GetParameter (pos).Name;
316 public string ParameterDesc (int pos)
318 if (has_varargs && pos >= count)
321 string tmp = String.Empty;
322 Parameter p = GetParameter (pos);
325 // We need to and for REF/OUT, because if either is set the
326 // extra flag ISBYREF will be set as well
328 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
330 else if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
332 else if (p.ModFlags == Parameter.Modifier.PARAMS)
335 Type t = ParameterType (pos);
337 return tmp + TypeManager.CSharpName (t);
340 public Parameter.Modifier ParameterModifier (int pos)
342 if (has_varargs && pos >= count)
343 return Parameter.Modifier.ARGLIST;
345 Parameter.Modifier mod = GetParameter (pos).ModFlags;
347 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
348 mod |= Parameter.Modifier.ISBYREF;
355 class PtrHashtable : Hashtable {
356 sealed class PtrComparer : IComparer {
357 private PtrComparer () {}
359 public static PtrComparer Instance = new PtrComparer ();
361 public int Compare (object x, object y)
370 public PtrHashtable ()
372 comparer = PtrComparer.Instance;
377 * Hashtable whose keys are character arrays with the same length
379 class CharArrayHashtable : Hashtable {
380 sealed class ArrComparer : IComparer {
383 public ArrComparer (int len) {
387 public int Compare (object x, object y)
389 char[] a = (char[])x;
390 char[] b = (char[])y;
392 for (int i = 0; i < len; ++i)
401 protected override int GetHash (Object key)
403 char[] arr = (char[])key;
406 for (int i = 0; i < len; ++i)
407 h = (h << 5) - h + arr [i];
412 public CharArrayHashtable (int len)
415 comparer = new ArrComparer (len);
421 public object Second;
423 public Pair (object f, object s)
431 /// This is a wrapper around StreamReader which is seekable.
433 public class SeekableStreamReader
435 public SeekableStreamReader (StreamReader reader)
437 this.reader = reader;
438 this.buffer = new char [DefaultCacheSize];
440 // Compute the preamble size
442 // Let the StreamWriter autodetect the encoder
445 reader.BaseStream.Position = 0;
446 Encoding enc = reader.CurrentEncoding;
447 // First of all, get at least a char
449 byte[] auxb = new byte [50];
454 br = reader.BaseStream.Read (auxb, num_bytes, auxb.Length - num_bytes);
456 num_chars = enc.GetCharCount (auxb, 0, num_bytes);
458 while (num_chars == 0 && br > 0);
462 // Now, check which bytes at the beginning have no effect in the
466 while (enc.GetCharCount (auxb, p, num_bytes-p) >= num_chars)
469 preamble_size = p - 1;
470 reader.BaseStream.Position = 0;
471 reader.DiscardBufferedData ();
473 buffer_start = preamble_size;
477 public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)
478 : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks))
483 private const int DefaultCacheSize = 1024;
486 int buffer_start; // in bytes
487 int buffer_size; // in bytes
488 int char_count; // count buffer[] valid characters
489 int pos; // index into buffer[]
493 /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
494 // always reports the correct position and if it's modified, it also takes care of the buffered data.
496 public int Position {
498 return buffer_start + reader.CurrentEncoding.GetByteCount (buffer, 0, pos);
502 // This one is easy: we're modifying the position within our current
504 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
505 int byte_offset = value - buffer_start;
507 // encoded characters can take more than 1 byte length
508 while (reader.CurrentEncoding.GetByteCount (buffer, 0, pos) > byte_offset)
514 if (value == 0) // Skip preamble
515 value = preamble_size;
517 // Ok, now we need to seek.
518 reader.DiscardBufferedData ();
519 reader.BaseStream.Position = buffer_start = value;
520 char_count = buffer_size = pos = 0;
524 private bool ReadBuffer ()
527 buffer_start += buffer_size;
528 char_count = reader.Read (buffer, 0, buffer.Length);
529 buffer_size = reader.CurrentEncoding.GetByteCount (buffer, 0, char_count);
530 return buffer_size > 0;
535 if ((pos >= char_count) && !ReadBuffer ())
543 if ((pos >= char_count) && !ReadBuffer ())
546 return buffer [pos++];
550 public class DoubleHash {
551 const int DEFAULT_INITIAL_BUCKETS = 100;
553 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
555 public DoubleHash (int size)
558 buckets = new Entry [size];
572 public Entry (object key1, object key2, int hash, object value, Entry next)
582 public bool Lookup (object a, object b, out object res)
584 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
586 for (Entry e = buckets [h % count]; e != null; e = e.next) {
587 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
596 public void Insert (object a, object b, object value)
598 // Is it an existing one?
600 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
602 for (Entry e = buckets [h % count]; e != null; e = e.next) {
603 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
607 int bucket = h % count;
608 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
610 // Grow whenever we double in size
611 if (size++ == count) {
615 Entry [] newBuckets = new Entry [count];
616 foreach (Entry root in buckets) {
619 int newLoc = e.hash % count;
621 e.next = newBuckets [newLoc];
622 newBuckets [newLoc] = e;
627 buckets = newBuckets;