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 {
35 bool last_arg_is_params = false;
36 bool is_varargs = false;
39 public ReflectionParameters (MethodBase mb)
43 ParameterInfo [] pi = mb.GetParameters ();
44 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
47 int count = pi.Length-1;
50 types = Type.EmptyTypes;
52 types = new Type [pi.Length];
53 for (int i = 0; i < pi.Length; i++)
54 types [i] = pi [i].ParameterType;
60 MethodBase generic = TypeManager.DropGenericMethodArguments (mb);
62 gpd = TypeManager.GetParameterData (generic);
63 last_arg_is_params = gpd.HasParams;
67 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
71 if (attrs.Length == 0)
74 last_arg_is_params = true;
77 public string GetSignatureForError ()
79 StringBuilder sb = new StringBuilder ("(");
80 for (int i = 0; i < pi.Length; ++i) {
83 sb.Append (ParameterDesc (i));
88 sb.Append ("__arglist");
91 return sb.ToString ();
94 public Type ParameterType (int pos)
96 if (last_arg_is_params && pos >= pi.Length - 1)
97 return pi [pi.Length - 1].ParameterType;
98 else if (is_varargs && pos >= pi.Length)
99 return TypeManager.runtime_argument_handle_type;
101 Type t = pi [pos].ParameterType;
107 public string ParameterName (int pos)
110 return gpd.ParameterName (pos);
112 if (last_arg_is_params && pos >= pi.Length - 1)
113 return pi [pi.Length - 1].Name;
114 else if (is_varargs && pos >= pi.Length)
117 return pi [pos].Name;
120 public string ParameterDesc (int pos)
122 if (is_varargs && pos >= pi.Length)
125 StringBuilder sb = new StringBuilder ();
130 Type partype = ParameterType (pos);
131 if (partype.IsByRef){
132 partype = TypeManager.GetElementType (partype);
139 if (pos >= pi.Length - 1 && last_arg_is_params)
140 sb.Append ("params ");
142 sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
144 return sb.ToString ();
147 public Parameter.Modifier ParameterModifier (int pos)
149 if (last_arg_is_params && pos >= pi.Length - 1)
150 return Parameter.Modifier.PARAMS;
151 else if (is_varargs && pos >= pi.Length)
152 return Parameter.Modifier.ARGLIST;
155 return gpd.ParameterModifier (pos);
157 Type t = pi [pos].ParameterType;
159 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
160 return Parameter.Modifier.OUT;
162 return Parameter.Modifier.REF;
165 return Parameter.Modifier.NONE;
169 get { return is_varargs ? pi.Length + 1 : pi.Length; }
172 public bool HasParams {
173 get { return last_arg_is_params; }
176 public Type[] Types {
177 get { return types; }
182 public class ReflectionConstraints : GenericConstraints
184 GenericParameterAttributes attrs;
186 Type class_constraint;
187 Type[] iface_constraints;
190 public static GenericConstraints GetConstraints (Type t)
192 Type [] constraints = t.GetGenericParameterConstraints ();
193 GenericParameterAttributes attrs = t.GenericParameterAttributes;
194 if (constraints.Length == 0 && attrs == GenericParameterAttributes.None)
196 return new ReflectionConstraints (t.Name, constraints, attrs);
199 private ReflectionConstraints (string name, Type [] constraints, GenericParameterAttributes attrs)
204 if ((constraints.Length > 0) && !constraints [0].IsInterface) {
205 class_constraint = constraints [0];
206 iface_constraints = new Type [constraints.Length - 1];
207 Array.Copy (constraints, 1, iface_constraints, 0, constraints.Length - 1);
209 iface_constraints = constraints;
211 if (HasValueTypeConstraint)
212 base_type = TypeManager.value_type;
213 else if (class_constraint != null)
214 base_type = class_constraint;
216 base_type = TypeManager.object_type;
219 public override string TypeParameter {
223 public override GenericParameterAttributes Attributes {
224 get { return attrs; }
227 public override Type ClassConstraint {
228 get { return class_constraint; }
231 public override Type EffectiveBaseClass {
232 get { return base_type; }
235 public override Type[] InterfaceConstraints {
236 get { return iface_constraints; }
241 class PtrHashtable : Hashtable {
242 sealed class PtrComparer : IComparer {
243 private PtrComparer () {}
245 public static PtrComparer Instance = new PtrComparer ();
247 public int Compare (object x, object y)
256 public PtrHashtable ()
258 comparer = PtrComparer.Instance;
263 * Hashtable whose keys are character arrays with the same length
265 class CharArrayHashtable : Hashtable {
266 sealed class ArrComparer : IComparer {
269 public ArrComparer (int len) {
273 public int Compare (object x, object y)
275 char[] a = (char[])x;
276 char[] b = (char[])y;
278 for (int i = 0; i < len; ++i)
287 protected override int GetHash (Object key)
289 char[] arr = (char[])key;
292 for (int i = 0; i < len; ++i)
293 h = (h << 5) - h + arr [i];
298 public CharArrayHashtable (int len)
301 comparer = new ArrComparer (len);
307 public object Second;
309 public Pair (object f, object s)
317 /// This is a wrapper around StreamReader which is seekable backwards
318 /// within a window of around 2048 chars.
320 public class SeekableStreamReader
322 public SeekableStreamReader (StreamReader reader)
324 this.reader = reader;
325 this.buffer = new char [AverageReadLength * 3];
327 // Let the StreamWriter autodetect the encoder
331 public SeekableStreamReader (Stream stream, Encoding encoding)
332 : this (new StreamReader (stream, encoding, true))
337 private const int AverageReadLength = 1024;
340 int buffer_start; // in chars
341 int char_count; // count buffer[] valid characters
342 int pos; // index into buffer[]
345 /// This value corresponds to the current position in a stream of characters.
346 /// The StreamReader hides its manipulation of the underlying byte stream and all
347 /// character set/decoding issues. Thus, we cannot use this position to guess at
348 /// the corresponding position in the underlying byte stream even though there is
349 /// a correlation between them.
351 public int Position {
352 get { return buffer_start + pos; }
355 if (value < buffer_start || value > buffer_start + char_count)
356 throw new InternalErrorException ("can't seek that far back: " + (pos - value));
357 pos = value - buffer_start;
361 private bool ReadBuffer ()
363 int slack = buffer.Length - char_count;
364 if (slack <= AverageReadLength / 2) {
365 // shift the buffer to make room for AverageReadLength number of characters
366 int shift = AverageReadLength - slack;
367 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
370 buffer_start += shift;
371 slack += shift; // slack == AverageReadLength
374 int chars_read = reader.Read (buffer, char_count, slack);
375 char_count += chars_read;
377 return pos < char_count;
382 if ((pos >= char_count) && !ReadBuffer ())
390 if ((pos >= char_count) && !ReadBuffer ())
393 return buffer [pos++];
397 public class DoubleHash {
398 const int DEFAULT_INITIAL_BUCKETS = 100;
400 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
402 public DoubleHash (int size)
405 buckets = new Entry [size];
419 public Entry (object key1, object key2, int hash, object value, Entry next)
429 public bool Lookup (object a, object b, out object res)
431 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
433 for (Entry e = buckets [h % count]; e != null; e = e.next) {
434 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
443 public void Insert (object a, object b, object value)
445 // Is it an existing one?
447 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
449 for (Entry e = buckets [h % count]; e != null; e = e.next) {
450 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
454 int bucket = h % count;
455 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
457 // Grow whenever we double in size
458 if (size++ == count) {
462 Entry [] newBuckets = new Entry [count];
463 foreach (Entry root in buckets) {
466 int newLoc = e.hash % count;
468 e.next = newBuckets [newLoc];
469 newBuckets [newLoc] = e;
474 buckets = newBuckets;