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);
23 Type [] Types { get; }
25 bool HasParams { get; }
26 string ParameterName (int pos);
27 string ParameterDesc (int pos);
28 Parameter.Modifier ParameterModifier (int pos);
29 string GetSignatureForError ();
32 public class ReflectionParameters : ParameterData {
39 public ReflectionParameters (MethodBase mb)
41 ParameterInfo [] pi = mb.GetParameters ();
42 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
45 int count = pi.Length;
48 types = Type.EmptyTypes;
52 types = new Type [count];
53 for (int i = 0; i < count; i++)
54 types [i] = pi [i].ParameterType;
56 // TODO: This (if) should be done one level higher to correctly use
57 // out caching facilities.
58 MethodBase generic = TypeManager.DropGenericMethodArguments (mb);
60 gpd = TypeManager.GetParameterData (generic);
62 for (int i = gpd.Count; i != 0; --i) {
63 if ((gpd.ParameterModifier (i)& Parameter.Modifier.PARAMS) != 0) {
73 // So far, the params attribute can be used in C# for the last
74 // and next to last method parameters.
75 // If some other language can place it anywhere we will
76 // have to analyze all parameters and not just last 2.
79 for (int i = count; i >= 0 && i > count - 2; --i) {
80 if (!pi [i].ParameterType.IsArray)
83 object [] attrs = pi [i].GetCustomAttributes (TypeManager.param_array_type, true);
84 if (attrs.Length == 1) {
91 public override bool Equals (object obj)
93 ReflectionParameters rp = obj as ReflectionParameters;
97 if (Count != rp.Count)
100 for (int i = 0; i < Count; ++i) {
101 if (!types [i].Equals (rp.types [i]))
107 public override int GetHashCode()
109 return base.GetHashCode ();
112 public string GetSignatureForError ()
114 StringBuilder sb = new StringBuilder ("(");
115 for (int i = 0; i < pi.Length; ++i) {
118 sb.Append (ParameterDesc (i));
123 sb.Append ("__arglist");
126 return sb.ToString ();
129 public Type ParameterType (int pos)
131 if (is_varargs && pos >= pi.Length)
132 return TypeManager.runtime_argument_handle_type;
134 return pi [pos].ParameterType;
137 public string ParameterName (int pos)
140 return gpd.ParameterName (pos);
142 if (is_varargs && pos >= pi.Length)
145 return pi [pos].Name;
148 public string ParameterDesc (int pos)
150 if (is_varargs && pos >= pi.Length)
153 StringBuilder sb = new StringBuilder ();
158 Type partype = ParameterType (pos);
159 if (partype.IsByRef){
160 partype = TypeManager.GetElementType (partype);
167 if (params_idx == pos)
168 sb.Append ("params ");
170 sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
172 return sb.ToString ();
175 public Parameter.Modifier ParameterModifier (int pos)
177 if (pos == params_idx)
178 return Parameter.Modifier.PARAMS;
179 else if (is_varargs && pos >= pi.Length)
180 return Parameter.Modifier.ARGLIST;
183 return gpd.ParameterModifier (pos);
185 Type t = pi [pos].ParameterType;
187 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
188 return Parameter.Modifier.OUT;
190 return Parameter.Modifier.REF;
193 return Parameter.Modifier.NONE;
197 get { return is_varargs ? pi.Length + 1 : pi.Length; }
200 public bool HasParams {
201 get { return params_idx != -1; }
204 public Type[] Types {
205 get { return types; }
210 public class ReflectionConstraints : GenericConstraints
212 GenericParameterAttributes attrs;
214 Type class_constraint;
215 Type[] iface_constraints;
218 public static GenericConstraints GetConstraints (Type t)
220 Type [] constraints = t.GetGenericParameterConstraints ();
221 GenericParameterAttributes attrs = t.GenericParameterAttributes;
222 if (constraints.Length == 0 && attrs == GenericParameterAttributes.None)
224 return new ReflectionConstraints (t.Name, constraints, attrs);
227 private ReflectionConstraints (string name, Type [] constraints, GenericParameterAttributes attrs)
232 if ((constraints.Length > 0) && !constraints [0].IsInterface) {
233 class_constraint = constraints [0];
234 iface_constraints = new Type [constraints.Length - 1];
235 Array.Copy (constraints, 1, iface_constraints, 0, constraints.Length - 1);
237 iface_constraints = constraints;
239 if (HasValueTypeConstraint)
240 base_type = TypeManager.value_type;
241 else if (class_constraint != null)
242 base_type = class_constraint;
244 base_type = TypeManager.object_type;
247 public override string TypeParameter {
251 public override GenericParameterAttributes Attributes {
252 get { return attrs; }
255 public override Type ClassConstraint {
256 get { return class_constraint; }
259 public override Type EffectiveBaseClass {
260 get { return base_type; }
263 public override Type[] InterfaceConstraints {
264 get { return iface_constraints; }
269 class PtrHashtable : Hashtable {
270 sealed class PtrComparer : IComparer {
271 private PtrComparer () {}
273 public static PtrComparer Instance = new PtrComparer ();
275 public int Compare (object x, object y)
284 public PtrHashtable ()
286 comparer = PtrComparer.Instance;
291 * Hashtable whose keys are character arrays with the same length
293 class CharArrayHashtable : Hashtable {
294 sealed class ArrComparer : IComparer {
297 public ArrComparer (int len) {
301 public int Compare (object x, object y)
303 char[] a = (char[])x;
304 char[] b = (char[])y;
306 for (int i = 0; i < len; ++i)
315 protected override int GetHash (Object key)
317 char[] arr = (char[])key;
320 for (int i = 0; i < len; ++i)
321 h = (h << 5) - h + arr [i];
326 public CharArrayHashtable (int len)
329 comparer = new ArrComparer (len);
335 public object Second;
337 public Pair (object f, object s)
345 /// This is a wrapper around StreamReader which is seekable backwards
346 /// within a window of around 2048 chars.
348 public class SeekableStreamReader
350 public SeekableStreamReader (StreamReader reader)
352 this.reader = reader;
353 this.buffer = new char [AverageReadLength * 3];
355 // Let the StreamWriter autodetect the encoder
359 public SeekableStreamReader (Stream stream, Encoding encoding)
360 : this (new StreamReader (stream, encoding, true))
365 private const int AverageReadLength = 1024;
368 int buffer_start; // in chars
369 int char_count; // count buffer[] valid characters
370 int pos; // index into buffer[]
373 /// This value corresponds to the current position in a stream of characters.
374 /// The StreamReader hides its manipulation of the underlying byte stream and all
375 /// character set/decoding issues. Thus, we cannot use this position to guess at
376 /// the corresponding position in the underlying byte stream even though there is
377 /// a correlation between them.
379 public int Position {
380 get { return buffer_start + pos; }
383 if (value < buffer_start || value > buffer_start + char_count)
384 throw new InternalErrorException ("can't seek that far back: " + (pos - value));
385 pos = value - buffer_start;
389 private bool ReadBuffer ()
391 int slack = buffer.Length - char_count;
392 if (slack <= AverageReadLength / 2) {
393 // shift the buffer to make room for AverageReadLength number of characters
394 int shift = AverageReadLength - slack;
395 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
398 buffer_start += shift;
399 slack += shift; // slack == AverageReadLength
402 int chars_read = reader.Read (buffer, char_count, slack);
403 char_count += chars_read;
405 return pos < char_count;
410 if ((pos >= char_count) && !ReadBuffer ())
418 if ((pos >= char_count) && !ReadBuffer ())
421 return buffer [pos++];
425 public class DoubleHash {
426 const int DEFAULT_INITIAL_BUCKETS = 100;
428 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
430 public DoubleHash (int size)
433 buckets = new Entry [size];
447 public Entry (object key1, object key2, int hash, object value, Entry next)
457 public bool Lookup (object a, object b, out object res)
459 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
461 for (Entry e = buckets [h % count]; e != null; e = e.next) {
462 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
471 public void Insert (object a, object b, object value)
473 // Is it an existing one?
475 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
477 for (Entry e = buckets [h % count]; e != null; e = e.next) {
478 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
482 int bucket = h % count;
483 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
485 // Grow whenever we double in size
486 if (size++ == count) {
490 Entry [] newBuckets = new Entry [count];
491 foreach (Entry root in buckets) {
494 int newLoc = e.hash % count;
496 e.next = newBuckets [newLoc];
497 newBuckets [newLoc] = e;
502 buckets = newBuckets;