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 {
42 bool last_arg_is_params = false;
45 public ReflectionParameters (MethodBase method)
49 this.pi = method.GetParameters ();
50 int count = pi.Length-1;
55 if (method.Mono_IsInflatedMethod) {
56 MethodInfo generic = method.GetGenericMethodDefinition ();
57 gpd = Invocation.GetParameterData (generic);
59 last_arg_is_params = gpd.HasArrayParameter;
63 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
67 if (attrs.Length == 0)
70 last_arg_is_params = true;
73 public bool HasArrayParameter {
74 get { return last_arg_is_params; }
77 public Type ParameterType (int pos)
79 if (last_arg_is_params && pos >= pi.Length - 1)
80 return pi [pi.Length - 1].ParameterType;
82 Type t = pi [pos].ParameterType;
88 public GenericConstraints GenericConstraints (int pos)
91 return gpd.GenericConstraints (pos);
93 Type t = ParameterType (pos);
94 if (!t.IsGenericParameter)
97 return ReflectionConstraints.Create (t);
100 public string ParameterName (int pos)
102 if (last_arg_is_params && pos >= pi.Length - 1)
103 return pi [pi.Length - 1].Name;
105 return pi [pos].Name;
108 public string ParameterDesc (int pos)
110 StringBuilder sb = new StringBuilder ();
115 Type partype = ParameterType (pos);
116 if (partype.IsByRef){
117 partype = TypeManager.GetElementType (partype);
124 if (pos >= pi.Length - 1 && last_arg_is_params)
125 sb.Append ("params ");
127 sb.Append (TypeManager.CSharpName (partype));
129 return sb.ToString ();
133 public Parameter.Modifier ParameterModifier (int pos)
138 if (last_arg_is_params)
139 return Parameter.Modifier.PARAMS;
141 Type t = pi [pos].ParameterType;
143 if ((pi [pos].Attributes & ParameterAttributes.Out) != 0)
144 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
146 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
149 return Parameter.Modifier.NONE;
158 protected class ReflectionConstraints : GenericConstraints
161 bool is_reference_type;
163 Type class_constraint;
164 Type[] iface_constraints;
166 protected ReflectionConstraints (bool has_ctor, Type class_constr,
167 Type[] iface_constrs)
169 this.has_ctor = has_ctor;
170 this.class_constraint = class_constr;
171 this.iface_constraints = iface_constrs;
173 if (class_constraint != null) {
174 if (class_constraint == TypeManager.object_type)
175 is_reference_type = true;
176 else if (class_constraint == TypeManager.value_type)
177 is_value_type = true;
181 public static GenericConstraints Create (Type t)
183 Type class_constr = null;
184 Type[] iface_constrs = t.GetInterfaces ();
185 if (iface_constrs == null)
186 iface_constrs = Type.EmptyTypes;
187 if (t.BaseType != TypeManager.object_type)
188 class_constr = t.BaseType;
190 return new ReflectionConstraints (
191 false, class_constr, iface_constrs);
194 public bool HasConstructor {
195 get { return has_ctor; }
198 public bool HasClassConstraint {
199 get { return class_constraint != null; }
202 public bool IsReferenceType {
203 get { return is_reference_type; }
206 public bool IsValueType {
207 get { return is_value_type; }
210 public Type ClassConstraint {
211 get { return class_constraint; }
214 public Type[] InterfaceConstraints {
215 get { return iface_constraints; }
220 public class InternalParameters : ParameterData {
223 public readonly Parameters Parameters;
225 public InternalParameters (Type [] param_types, Parameters parameters)
227 this.param_types = param_types;
228 this.Parameters = parameters;
231 public InternalParameters (DeclSpace ds, Parameters parameters)
232 : this (parameters.GetParameterInfo (ds), parameters)
238 if (param_types == null)
241 return param_types.Length;
245 public bool HasArrayParameter {
246 get { return Parameters.ArrayParameter != null; }
249 Parameter GetParameter (int pos)
251 Parameter [] fixed_pars = Parameters.FixedParameters;
252 if (fixed_pars != null){
253 int len = fixed_pars.Length;
255 return Parameters.FixedParameters [pos];
258 return Parameters.ArrayParameter;
261 public Type ParameterType (int pos)
263 if (param_types == null)
266 return GetParameter (pos).ExternalType ();
269 public GenericConstraints GenericConstraints (int pos)
271 if (param_types == null)
274 return GetParameter (pos).GenericConstraints;
277 public string ParameterName (int pos)
279 return GetParameter (pos).Name;
282 public string ParameterDesc (int pos)
284 string tmp = String.Empty;
285 Parameter p = GetParameter (pos);
288 // We need to and for REF/OUT, because if either is set the
289 // extra flag ISBYREF will be set as well
291 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
293 else if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
295 else if (p.ModFlags == Parameter.Modifier.PARAMS)
298 Type t = ParameterType (pos);
300 return tmp + TypeManager.CSharpName (t);
303 public Parameter.Modifier ParameterModifier (int pos)
305 Parameter.Modifier mod = GetParameter (pos).ModFlags;
307 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
308 mod |= Parameter.Modifier.ISBYREF;
315 class PtrHashtable : Hashtable {
316 sealed class PtrComparer : IComparer {
317 private PtrComparer () {}
319 public static PtrComparer Instance = new PtrComparer ();
321 public int Compare (object x, object y)
330 public PtrHashtable ()
332 comparer = PtrComparer.Instance;
337 * Hashtable whose keys are character arrays with the same length
339 class CharArrayHashtable : Hashtable {
340 sealed class ArrComparer : IComparer {
343 public ArrComparer (int len) {
347 public int Compare (object x, object y)
349 char[] a = (char[])x;
350 char[] b = (char[])y;
352 for (int i = 0; i < len; ++i)
361 protected override int GetHash (Object key)
363 char[] arr = (char[])key;
366 for (int i = 0; i < len; ++i)
367 h = (h << 5) - h + arr [i];
372 public CharArrayHashtable (int len)
375 comparer = new ArrComparer (len);
380 // Compares member infos based on their name and
381 // also allows one argument to be a string
383 class MemberInfoCompare : IComparer {
385 public int Compare (object a, object b)
387 if (a == null || b == null){
388 Console.WriteLine ("Invalid information passed");
389 throw new Exception ();
393 return String.Compare ((string) a, ((MemberInfo)b).Name, false, CultureInfo.InvariantCulture);
396 return String.Compare (((MemberInfo)a).Name, (string) b, false, CultureInfo.InvariantCulture);
398 return String.Compare (((MemberInfo)a).Name, ((MemberInfo)b).Name, false, CultureInfo.InvariantCulture);
404 public object Second;
406 public Pair (object f, object s)
414 /// This is a wrapper around StreamReader which is seekable.
416 public class SeekableStreamReader
418 public SeekableStreamReader (StreamReader reader)
420 this.reader = reader;
421 this.buffer = new char [DefaultCacheSize];
423 // Compute the preamble size
425 // Let the StreamWriter autodetect the encoder
428 reader.BaseStream.Position = 0;
429 Encoding enc = reader.CurrentEncoding;
430 // First of all, get at least a char
432 byte[] auxb = new byte [50];
437 br = reader.BaseStream.Read (auxb, num_bytes, auxb.Length - num_bytes);
439 num_chars = enc.GetCharCount (auxb, 0, num_bytes);
441 while (num_chars == 0 && br > 0);
445 // Now, check which bytes at the beginning have no effect in the
449 while (enc.GetCharCount (auxb, p, num_bytes-p) >= num_chars)
452 preamble_size = p - 1;
453 reader.BaseStream.Position = 0;
454 reader.DiscardBufferedData ();
456 buffer_start = preamble_size;
460 public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)
461 : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks))
466 private const int DefaultCacheSize = 1024;
469 int buffer_start; // in bytes
470 int buffer_size; // in bytes
471 int char_count; // count buffer[] valid characters
472 int pos; // index into buffer[]
476 /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
477 // always reports the correct position and if it's modified, it also takes care of the buffered data.
479 public int Position {
481 return buffer_start + reader.CurrentEncoding.GetByteCount (buffer, 0, pos);
485 // This one is easy: we're modifying the position within our current
487 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
488 int byte_offset = value - buffer_start;
490 // encoded characters can take more than 1 byte length
491 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;