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; }
26 public interface ParameterData {
27 Type ParameterType (int pos);
28 GenericConstraints GenericConstraints (int pos);
29 bool HasArrayParameter { get; }
31 string ParameterName (int pos);
32 string ParameterDesc (int pos);
33 Parameter.Modifier ParameterModifier (int pos);
36 public class ReflectionParameters : ParameterData {
38 bool last_arg_is_params = false;
41 public ReflectionParameters (MethodBase method)
45 this.pi = method.GetParameters ();
46 int count = pi.Length-1;
51 if (method.HasGenericParameters) {
52 MethodInfo generic = method.GetGenericMethodDefinition ();
53 if (generic != method) {
54 gpd = Invocation.GetParameterData (generic);
56 last_arg_is_params = gpd.HasArrayParameter;
61 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
65 if (attrs.Length == 0)
68 last_arg_is_params = true;
71 public bool HasArrayParameter {
72 get { return last_arg_is_params; }
75 public Type ParameterType (int pos)
77 if (last_arg_is_params && pos >= pi.Length - 1)
78 return pi [pi.Length - 1].ParameterType;
80 Type t = pi [pos].ParameterType;
86 public GenericConstraints GenericConstraints (int pos)
89 return gpd.GenericConstraints (pos);
91 Type t = ParameterType (pos);
92 if (!t.IsGenericParameter)
95 return ReflectionConstraints.Create (t);
98 public string ParameterName (int pos)
100 if (last_arg_is_params && pos >= pi.Length - 1)
101 return pi [pi.Length - 1].Name;
103 return pi [pos].Name;
106 public string ParameterDesc (int pos)
108 StringBuilder sb = new StringBuilder ();
113 Type partype = ParameterType (pos);
114 if (partype.IsByRef){
115 partype = TypeManager.GetElementType (partype);
122 if (pos >= pi.Length - 1 && last_arg_is_params)
123 sb.Append ("params ");
125 sb.Append (TypeManager.CSharpName (partype));
127 return sb.ToString ();
131 public Parameter.Modifier ParameterModifier (int pos)
136 if (last_arg_is_params)
137 return Parameter.Modifier.PARAMS;
139 Type t = pi [pos].ParameterType;
141 if ((pi [pos].Attributes & ParameterAttributes.Out) != 0)
142 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
144 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
147 return Parameter.Modifier.NONE;
156 protected class ReflectionConstraints : GenericConstraints
161 protected ReflectionConstraints (bool has_ctor, Type[] types)
163 this.has_ctor = has_ctor;
167 public static GenericConstraints Create (Type t)
170 Type[] ifaces = t.GetInterfaces ();
171 if (t.BaseType != TypeManager.object_type) {
172 types = new Type [ifaces.Length + 1];
173 types [0] = t.BaseType;
174 ifaces.CopyTo (types, 1);
176 types = new Type [ifaces.Length];
177 ifaces.CopyTo (types, 0);
180 if (types.Length == 0)
183 return new ReflectionConstraints (false, types);
186 public bool HasConstructor {
192 public Type[] Types {
200 public class InternalParameters : ParameterData {
203 public readonly Parameters Parameters;
205 public InternalParameters (Type [] param_types, Parameters parameters)
207 this.param_types = param_types;
208 this.Parameters = parameters;
211 public InternalParameters (DeclSpace ds, Parameters parameters)
212 : this (parameters.GetParameterInfo (ds), parameters)
218 if (param_types == null)
221 return param_types.Length;
225 public bool HasArrayParameter {
226 get { return Parameters.ArrayParameter != null; }
229 Parameter GetParameter (int pos)
231 Parameter [] fixed_pars = Parameters.FixedParameters;
232 if (fixed_pars != null){
233 int len = fixed_pars.Length;
235 return Parameters.FixedParameters [pos];
238 return Parameters.ArrayParameter;
241 public Type ParameterType (int pos)
243 if (param_types == null)
246 return GetParameter (pos).ExternalType ();
249 public GenericConstraints GenericConstraints (int pos)
251 if (param_types == null)
254 return GetParameter (pos).GenericConstraints;
257 public string ParameterName (int pos)
259 return GetParameter (pos).Name;
262 public string ParameterDesc (int pos)
264 string tmp = String.Empty;
265 Parameter p = GetParameter (pos);
268 // We need to and for REF/OUT, because if either is set the
269 // extra flag ISBYREF will be set as well
271 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
273 else if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
275 else if (p.ModFlags == Parameter.Modifier.PARAMS)
278 Type t = ParameterType (pos);
280 return tmp + TypeManager.CSharpName (t);
283 public Parameter.Modifier ParameterModifier (int pos)
285 Parameter.Modifier mod = GetParameter (pos).ModFlags;
287 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
288 mod |= Parameter.Modifier.ISBYREF;
295 class PtrHashtable : Hashtable {
296 sealed class PtrComparer : IComparer {
297 private PtrComparer () {}
299 public static PtrComparer Instance = new PtrComparer ();
301 public int Compare (object x, object y)
310 public PtrHashtable ()
312 comparer = PtrComparer.Instance;
317 * Hashtable whose keys are character arrays with the same length
319 class CharArrayHashtable : Hashtable {
320 sealed class ArrComparer : IComparer {
323 public ArrComparer (int len) {
327 public int Compare (object x, object y)
329 char[] a = (char[])x;
330 char[] b = (char[])y;
332 for (int i = 0; i < len; ++i)
341 protected override int GetHash (Object key)
343 char[] arr = (char[])key;
346 for (int i = 0; i < len; ++i)
347 h = (h << 5) - h + arr [i];
352 public CharArrayHashtable (int len)
355 comparer = new ArrComparer (len);
360 // Compares member infos based on their name and
361 // also allows one argument to be a string
363 class MemberInfoCompare : IComparer {
365 public int Compare (object a, object b)
367 if (a == null || b == null){
368 Console.WriteLine ("Invalid information passed");
369 throw new Exception ();
373 return String.Compare ((string) a, ((MemberInfo)b).Name, false, CultureInfo.InvariantCulture);
376 return String.Compare (((MemberInfo)a).Name, (string) b, false, CultureInfo.InvariantCulture);
378 return String.Compare (((MemberInfo)a).Name, ((MemberInfo)b).Name, false, CultureInfo.InvariantCulture);
384 public object Second;
386 public Pair (object f, object s)
394 /// This is a wrapper around StreamReader which is seekable.
396 public class SeekableStreamReader
398 public SeekableStreamReader (StreamReader reader)
400 this.reader = reader;
401 this.buffer = new char [DefaultCacheSize];
404 public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)
405 : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks))
410 private const int DefaultCacheSize = 1024;
413 int buffer_start; // in bytes
414 int buffer_size; // in bytes
415 int char_count; // count buffer[] valid characters
416 int pos; // index into buffer[]
419 /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
420 // always reports the correct position and if it's modified, it also takes care of the buffered data.
422 public int Position {
424 return buffer_start + reader.CurrentEncoding.GetByteCount (buffer, 0, pos);
428 // This one is easy: we're modifying the position within our current
430 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
431 int byte_offset = value - buffer_start;
433 // encoded characters can take more than 1 byte length
434 while (reader.CurrentEncoding.GetByteCount (buffer, 0, pos) > byte_offset)
440 // Ok, now we need to seek.
441 reader.DiscardBufferedData ();
442 reader.BaseStream.Position = buffer_start = value;
443 char_count = buffer_size = pos = 0;
447 private bool ReadBuffer ()
450 buffer_start += buffer_size;
451 char_count = reader.Read (buffer, 0, buffer.Length);
452 buffer_size = reader.CurrentEncoding.GetByteCount (buffer, 0, char_count);
453 return buffer_size > 0;
458 if ((pos >= char_count) && !ReadBuffer ())
466 if ((pos >= char_count) && !ReadBuffer ())
469 return buffer [pos++];
473 public class DoubleHash {
474 const int DEFAULT_INITIAL_BUCKETS = 100;
476 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
478 public DoubleHash (int size)
481 buckets = new Entry [size];
495 public Entry (object key1, object key2, int hash, object value, Entry next)
505 public bool Lookup (object a, object b, out object res)
507 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
509 for (Entry e = buckets [h % count]; e != null; e = e.next) {
510 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
519 public void Insert (object a, object b, object value)
521 // Is it an existing one?
523 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
525 for (Entry e = buckets [h % count]; e != null; e = e.next) {
526 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
530 int bucket = h % count;
531 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
533 // Grow whenever we double in size
534 if (size++ == count) {
538 Entry [] newBuckets = new Entry [count];
539 foreach (Entry root in buckets) {
542 int newLoc = e.hash % count;
544 e.next = newBuckets [newLoc];
545 newBuckets [newLoc] = e;
550 buckets = newBuckets;