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 bool HasParams { get; }
25 string ParameterName (int pos);
26 string ParameterDesc (int pos);
27 Parameter.Modifier ParameterModifier (int pos);
30 public class ReflectionParameters : ParameterData {
32 bool last_arg_is_params = false;
33 bool is_varargs = false;
35 public ReflectionParameters (MethodBase mb)
39 ParameterInfo [] pi = mb.GetParameters ();
40 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
43 int count = pi.Length-1;
46 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
51 if (attrs.Length == 0)
54 last_arg_is_params = true;
58 public Type ParameterType (int pos)
60 if (last_arg_is_params && pos >= pi.Length - 1)
61 return pi [pi.Length - 1].ParameterType;
62 else if (is_varargs && pos >= pi.Length)
63 return TypeManager.runtime_argument_handle_type;
65 Type t = pi [pos].ParameterType;
71 public string ParameterName (int pos)
73 if (last_arg_is_params && pos >= pi.Length - 1)
74 return pi [pi.Length - 1].Name;
75 else if (is_varargs && pos >= pi.Length)
81 public string ParameterDesc (int pos)
83 if (is_varargs && pos >= pi.Length)
86 StringBuilder sb = new StringBuilder ();
91 Type partype = ParameterType (pos);
93 partype = TypeManager.GetElementType (partype);
100 if (pos >= pi.Length - 1 && last_arg_is_params)
101 sb.Append ("params ");
103 sb.Append (TypeManager.CSharpName (partype));
105 return sb.ToString ();
109 public Parameter.Modifier ParameterModifier (int pos)
111 if (last_arg_is_params && pos >= pi.Length - 1)
112 return Parameter.Modifier.PARAMS;
113 else if (is_varargs && pos >= pi.Length)
114 return Parameter.Modifier.ARGLIST;
116 Type t = pi [pos].ParameterType;
118 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
119 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
121 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
124 return Parameter.Modifier.NONE;
129 return is_varargs ? pi.Length + 1 : pi.Length;
133 public bool HasParams {
135 return this.last_arg_is_params;
141 public class InternalParameters : ParameterData {
146 public readonly Parameters Parameters;
148 public InternalParameters (Type [] param_types, Parameters parameters)
150 this.param_types = param_types;
151 this.Parameters = parameters;
153 has_varargs = parameters.HasArglist;
155 if (param_types == null)
158 count = param_types.Length;
163 return has_varargs ? count + 1 : count;
167 public bool HasParams {
169 return Parameters.ArrayParameter != null;
173 Parameter GetParameter (int pos)
175 Parameter [] fixed_pars = Parameters.FixedParameters;
176 if (fixed_pars != null){
177 int len = fixed_pars.Length;
179 return Parameters.FixedParameters [pos];
182 return Parameters.ArrayParameter;
185 public Type ParameterType (int pos)
187 if (has_varargs && pos >= count)
188 return TypeManager.runtime_argument_handle_type;
190 if (param_types == null)
193 return GetParameter (pos).ExternalType ();
197 public string ParameterName (int pos)
199 if (has_varargs && pos >= count)
202 return GetParameter (pos).Name;
205 public string ParameterDesc (int pos)
207 if (has_varargs && pos >= count)
210 Type t = ParameterType (pos);
211 return ModifierDesc (pos) + " " + TypeManager.CSharpName (t);
214 public string ModifierDesc (int pos)
216 Parameter p = GetParameter (pos);
219 // We need to and for REF/OUT, because if either is set the
220 // extra flag ISBYREF will be set as well
222 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
224 if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
226 if (p.ModFlags == Parameter.Modifier.PARAMS)
232 public Parameter.Modifier ParameterModifier (int pos)
234 if (has_varargs && pos >= count)
235 return Parameter.Modifier.ARGLIST;
237 Parameter.Modifier mod = GetParameter (pos).ModFlags;
239 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
240 mod |= Parameter.Modifier.ISBYREF;
247 class PtrHashtable : Hashtable {
248 sealed class PtrComparer : IComparer {
249 private PtrComparer () {}
251 public static PtrComparer Instance = new PtrComparer ();
253 public int Compare (object x, object y)
262 public PtrHashtable ()
264 comparer = PtrComparer.Instance;
269 * Hashtable whose keys are character arrays with the same length
271 class CharArrayHashtable : Hashtable {
272 sealed class ArrComparer : IComparer {
275 public ArrComparer (int len) {
279 public int Compare (object x, object y)
281 char[] a = (char[])x;
282 char[] b = (char[])y;
284 for (int i = 0; i < len; ++i)
293 protected override int GetHash (Object key)
295 char[] arr = (char[])key;
298 for (int i = 0; i < len; ++i)
299 h = (h << 5) - h + arr [i];
304 public CharArrayHashtable (int len)
307 comparer = new ArrComparer (len);
313 public object Second;
315 public Pair (object f, object s)
323 /// This is a wrapper around StreamReader which is seekable.
325 public class SeekableStreamReader
327 public SeekableStreamReader (StreamReader reader)
329 this.reader = reader;
330 this.buffer = new char [DefaultCacheSize];
332 // Compute the preamble size
334 // Let the StreamWriter autodetect the encoder
337 reader.BaseStream.Position = 0;
338 Encoding enc = reader.CurrentEncoding;
339 // First of all, get at least a char
341 byte[] auxb = new byte [50];
346 br = reader.BaseStream.Read (auxb, num_bytes, auxb.Length - num_bytes);
348 num_chars = enc.GetCharCount (auxb, 0, num_bytes);
350 while (num_chars == 0 && br > 0);
354 // Now, check which bytes at the beginning have no effect in the
358 while (enc.GetCharCount (auxb, p, num_bytes-p) >= num_chars)
361 preamble_size = p - 1;
362 reader.BaseStream.Position = 0;
363 reader.DiscardBufferedData ();
365 buffer_start = preamble_size;
369 public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)
370 : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks))
375 private const int DefaultCacheSize = 1024;
378 int buffer_start; // in bytes
379 int buffer_size; // in bytes
380 int char_count; // count buffer[] valid characters
381 int pos; // index into buffer[]
385 /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
386 // always reports the correct position and if it's modified, it also takes care of the buffered data.
388 public int Position {
390 return buffer_start + reader.CurrentEncoding.GetByteCount (buffer, 0, pos);
394 // This one is easy: we're modifying the position within our current
396 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
397 int byte_offset = value - buffer_start;
399 // pos is an index into a char
400 // buffer so it might be
401 // greater than the buffer
402 // length now, if the buffer
403 // contains multibyte chars
406 // encoded characters can take
407 // more than 1 byte length.
408 while ((pos > buffer.Length) ||
409 reader.CurrentEncoding.GetByteCount (buffer, 0, pos) > byte_offset) {
416 if (value == 0) // Skip preamble
417 value = preamble_size;
419 // Ok, now we need to seek.
420 reader.DiscardBufferedData ();
421 reader.BaseStream.Position = buffer_start = value;
422 char_count = buffer_size = pos = 0;
426 private bool ReadBuffer ()
429 buffer_start += buffer_size;
430 char_count = reader.Read (buffer, 0, buffer.Length);
431 buffer_size = reader.CurrentEncoding.GetByteCount (buffer, 0, char_count);
432 return buffer_size > 0;
437 if ((pos >= char_count) && !ReadBuffer ())
445 if ((pos >= char_count) && !ReadBuffer ())
448 return buffer [pos++];
452 public class DoubleHash {
453 const int DEFAULT_INITIAL_BUCKETS = 100;
455 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
457 public DoubleHash (int size)
460 buckets = new Entry [size];
474 public Entry (object key1, object key2, int hash, object value, Entry next)
484 public bool Lookup (object a, object b, out object res)
486 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
488 for (Entry e = buckets [h % count]; e != null; e = e.next) {
489 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
498 public void Insert (object a, object b, object value)
500 // Is it an existing one?
502 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
504 for (Entry e = buckets [h % count]; e != null; e = e.next) {
505 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
509 int bucket = h % count;
510 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
512 // Grow whenever we double in size
513 if (size++ == count) {
517 Entry [] newBuckets = new Entry [count];
518 foreach (Entry root in buckets) {
521 int newLoc = e.hash % count;
523 e.next = newBuckets [newLoc];
524 newBuckets [newLoc] = e;
529 buckets = newBuckets;