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);
24 string ParameterName (int pos);
25 string ParameterDesc (int pos);
26 Parameter.Modifier ParameterModifier (int pos);
29 public class ReflectionParameters : ParameterData {
31 bool last_arg_is_params = false;
33 public ReflectionParameters (ParameterInfo [] pi)
38 int count = pi.Length-1;
41 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
46 if (attrs.Length == 0)
49 last_arg_is_params = true;
53 public Type ParameterType (int pos)
55 if (last_arg_is_params && pos >= pi.Length - 1)
56 return pi [pi.Length - 1].ParameterType;
58 Type t = pi [pos].ParameterType;
64 public string ParameterName (int pos)
66 if (last_arg_is_params && pos >= pi.Length - 1)
67 return pi [pi.Length - 1].Name;
72 public string ParameterDesc (int pos)
74 StringBuilder sb = new StringBuilder ();
79 Type partype = ParameterType (pos);
81 partype = TypeManager.GetElementType (partype);
88 if (pos >= pi.Length - 1 && last_arg_is_params)
89 sb.Append ("params ");
91 sb.Append (TypeManager.CSharpName (partype));
93 return sb.ToString ();
97 public Parameter.Modifier ParameterModifier (int pos)
102 if (last_arg_is_params)
103 return Parameter.Modifier.PARAMS;
105 Type t = pi [pos].ParameterType;
107 if ((pi [pos].Attributes & ParameterAttributes.Out) != 0)
108 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
110 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
113 return Parameter.Modifier.NONE;
124 public class InternalParameters : ParameterData {
127 public readonly Parameters Parameters;
129 public InternalParameters (Type [] param_types, Parameters parameters)
131 this.param_types = param_types;
132 this.Parameters = parameters;
135 public InternalParameters (DeclSpace ds, Parameters parameters)
136 : this (parameters.GetParameterInfo (ds), parameters)
142 if (param_types == null)
145 return param_types.Length;
149 Parameter GetParameter (int pos)
151 Parameter [] fixed_pars = Parameters.FixedParameters;
152 if (fixed_pars != null){
153 int len = fixed_pars.Length;
155 return Parameters.FixedParameters [pos];
158 return Parameters.ArrayParameter;
161 public Type ParameterType (int pos)
163 if (param_types == null)
166 return GetParameter (pos).ExternalType ();
170 public string ParameterName (int pos)
172 return GetParameter (pos).Name;
175 public string ParameterDesc (int pos)
177 string tmp = String.Empty;
178 Parameter p = GetParameter (pos);
181 // We need to and for REF/OUT, because if either is set the
182 // extra flag ISBYREF will be set as well
184 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
186 else if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
188 else if (p.ModFlags == Parameter.Modifier.PARAMS)
191 Type t = ParameterType (pos);
193 return tmp + TypeManager.CSharpName (t);
196 public Parameter.Modifier ParameterModifier (int pos)
198 Parameter.Modifier mod = GetParameter (pos).ModFlags;
200 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
201 mod |= Parameter.Modifier.ISBYREF;
208 class PtrHashtable : Hashtable {
209 sealed class PtrComparer : IComparer {
210 private PtrComparer () {}
212 public static PtrComparer Instance = new PtrComparer ();
214 public int Compare (object x, object y)
223 public PtrHashtable ()
225 comparer = PtrComparer.Instance;
230 * Hashtable whose keys are character arrays with the same length
232 class CharArrayHashtable : Hashtable {
233 sealed class ArrComparer : IComparer {
236 public ArrComparer (int len) {
240 public int Compare (object x, object y)
242 char[] a = (char[])x;
243 char[] b = (char[])y;
245 for (int i = 0; i < len; ++i)
254 protected override int GetHash (Object key)
256 char[] arr = (char[])key;
259 for (int i = 0; i < len; ++i)
260 h = (h << 5) - h + arr [i];
265 public CharArrayHashtable (int len)
268 comparer = new ArrComparer (len);
273 // Compares member infos based on their name and
274 // also allows one argument to be a string
276 class MemberInfoCompare : IComparer {
278 public int Compare (object a, object b)
280 if (a == null || b == null){
281 Console.WriteLine ("Invalid information passed");
282 throw new Exception ();
286 return String.Compare ((string) a, ((MemberInfo)b).Name, false, CultureInfo.InvariantCulture);
289 return String.Compare (((MemberInfo)a).Name, (string) b, false, CultureInfo.InvariantCulture);
291 return String.Compare (((MemberInfo)a).Name, ((MemberInfo)b).Name, false, CultureInfo.InvariantCulture);
297 public object Second;
299 public Pair (object f, object s)
307 /// This is a wrapper around StreamReader which is seekable.
309 public class SeekableStreamReader
311 public SeekableStreamReader (StreamReader reader)
313 this.reader = reader;
314 this.buffer = new char [DefaultCacheSize];
317 public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)
318 : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks))
323 private const int DefaultCacheSize = 1024;
331 /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
332 // always reports the correct position and if it's modified, it also takes care of the buffered data.
334 public int Position {
336 return buffer_start + pos;
340 // This one is easy: we're modifying the position within our current
342 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
343 pos = value - buffer_start;
347 // Ok, now we need to seek.
348 reader.DiscardBufferedData ();
349 reader.BaseStream.Position = buffer_start = value;
350 buffer_size = pos = 0;
354 private bool ReadBuffer ()
357 buffer_start += buffer_size;
358 buffer_size = reader.Read (buffer, 0, buffer.Length);
359 return buffer_size > 0;
364 if ((pos >= buffer_size) && !ReadBuffer ())
372 if ((pos >= buffer_size) && !ReadBuffer ())
375 return buffer [pos++];
379 public class DoubleHash {
380 const int DEFAULT_INITIAL_BUCKETS = 100;
382 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
384 public DoubleHash (int size)
387 buckets = new Entry [size];
401 public Entry (object key1, object key2, int hash, object value, Entry next)
411 public bool Lookup (object a, object b, out object res)
413 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
415 for (Entry e = buckets [h % count]; e != null; e = e.next) {
416 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
425 public void Insert (object a, object b, object value)
427 // Is it an existing one?
429 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
431 for (Entry e = buckets [h % count]; e != null; e = e.next) {
432 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
436 int bucket = h % count;
437 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
439 // Grow whenever we double in size
440 if (size++ == count) {
444 Entry [] newBuckets = new Entry [count];
445 foreach (Entry root in buckets) {
448 int newLoc = e.hash % count;
450 e.next = newBuckets [newLoc];
451 newBuckets [newLoc] = e;
456 buckets = newBuckets;