(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / mcs / support.cs
blobc040ebe328c64fc57d8ff342371ede6e07aab76c
1 //
2 // support.cs: Support routines to work around the fact that System.Reflection.Emit
3 // can not introspect types that are being constructed
4 //
5 // Author:
6 // Miguel de Icaza (miguel@ximian.com)
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
11 using System;
12 using System.IO;
13 using System.Text;
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 int Count { get; }
24 string ParameterName (int pos);
25 string ParameterDesc (int pos);
26 Parameter.Modifier ParameterModifier (int pos);
29 public class ReflectionParameters : ParameterData {
30 ParameterInfo [] pi;
31 bool last_arg_is_params = false;
32 bool is_varargs = false;
34 public ReflectionParameters (MethodBase mb)
36 object [] attrs;
38 ParameterInfo [] pi = mb.GetParameters ();
39 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
41 this.pi = pi;
42 int count = pi.Length-1;
44 if (count >= 0) {
45 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
47 if (attrs == null)
48 return;
50 if (attrs.Length == 0)
51 return;
53 last_arg_is_params = true;
57 public Type ParameterType (int pos)
59 if (last_arg_is_params && pos >= pi.Length - 1)
60 return pi [pi.Length - 1].ParameterType;
61 else if (is_varargs && pos >= pi.Length)
62 return TypeManager.runtime_argument_handle_type;
63 else {
64 Type t = pi [pos].ParameterType;
66 return t;
70 public string ParameterName (int pos)
72 if (last_arg_is_params && pos >= pi.Length - 1)
73 return pi [pi.Length - 1].Name;
74 else if (is_varargs && pos >= pi.Length)
75 return "__arglist";
76 else
77 return pi [pos].Name;
80 public string ParameterDesc (int pos)
82 if (is_varargs && pos >= pi.Length)
83 return "";
85 StringBuilder sb = new StringBuilder ();
87 if (pi [pos].IsIn)
88 sb.Append ("in ");
90 Type partype = ParameterType (pos);
91 if (partype.IsByRef){
92 partype = TypeManager.GetElementType (partype);
93 if (pi [pos].IsOut)
94 sb.Append ("out ");
95 else
96 sb.Append ("ref ");
99 if (pos >= pi.Length - 1 && last_arg_is_params)
100 sb.Append ("params ");
102 sb.Append (TypeManager.CSharpName (partype));
104 return sb.ToString ();
108 public Parameter.Modifier ParameterModifier (int pos)
110 int len = pi.Length;
112 if (last_arg_is_params && pos >= pi.Length - 1)
113 return Parameter.Modifier.PARAMS;
114 else if (is_varargs && pos >= pi.Length)
115 return Parameter.Modifier.ARGLIST;
117 Type t = pi [pos].ParameterType;
118 if (t.IsByRef){
119 if ((pi [pos].Attributes & ParameterAttributes.Out) != 0)
120 return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
121 else
122 return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
125 return Parameter.Modifier.NONE;
128 public int Count {
129 get {
130 return is_varargs ? pi.Length + 1 : pi.Length;
136 public class InternalParameters : ParameterData {
137 Type [] param_types;
138 bool has_varargs;
139 int count;
141 public readonly Parameters Parameters;
143 public InternalParameters (Type [] param_types, Parameters parameters)
145 this.param_types = param_types;
146 this.Parameters = parameters;
148 has_varargs = parameters.HasArglist;
150 if (param_types == null)
151 count = 0;
152 else
153 count = param_types.Length;
156 public int Count {
157 get {
158 return has_varargs ? count + 1 : count;
162 Parameter GetParameter (int pos)
164 Parameter [] fixed_pars = Parameters.FixedParameters;
165 if (fixed_pars != null){
166 int len = fixed_pars.Length;
167 if (pos < len)
168 return Parameters.FixedParameters [pos];
171 return Parameters.ArrayParameter;
174 public Type ParameterType (int pos)
176 if (has_varargs && pos >= count)
177 return TypeManager.runtime_argument_handle_type;
179 if (param_types == null)
180 return null;
182 return GetParameter (pos).ExternalType ();
186 public string ParameterName (int pos)
188 if (has_varargs && pos >= count)
189 return "__arglist";
191 return GetParameter (pos).Name;
194 public string ParameterDesc (int pos)
196 if (has_varargs && pos >= count)
197 return "__arglist";
199 string tmp = String.Empty;
200 Parameter p = GetParameter (pos);
203 // We need to and for REF/OUT, because if either is set the
204 // extra flag ISBYREF will be set as well
206 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
207 tmp = "ref ";
208 else if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
209 tmp = "out ";
210 else if (p.ModFlags == Parameter.Modifier.PARAMS)
211 tmp = "params ";
213 Type t = ParameterType (pos);
215 return tmp + TypeManager.CSharpName (t);
218 public Parameter.Modifier ParameterModifier (int pos)
220 if (has_varargs && pos >= count)
221 return Parameter.Modifier.ARGLIST;
223 Parameter.Modifier mod = GetParameter (pos).ModFlags;
225 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
226 mod |= Parameter.Modifier.ISBYREF;
228 return mod;
233 class PtrHashtable : Hashtable {
234 sealed class PtrComparer : IComparer {
235 private PtrComparer () {}
237 public static PtrComparer Instance = new PtrComparer ();
239 public int Compare (object x, object y)
241 if (x == y)
242 return 0;
243 else
244 return 1;
248 public PtrHashtable ()
250 comparer = PtrComparer.Instance;
255 * Hashtable whose keys are character arrays with the same length
257 class CharArrayHashtable : Hashtable {
258 sealed class ArrComparer : IComparer {
259 private int len;
261 public ArrComparer (int len) {
262 this.len = len;
265 public int Compare (object x, object y)
267 char[] a = (char[])x;
268 char[] b = (char[])y;
270 for (int i = 0; i < len; ++i)
271 if (a [i] != b [i])
272 return 1;
273 return 0;
277 private int len;
279 protected override int GetHash (Object key)
281 char[] arr = (char[])key;
282 int h = 0;
284 for (int i = 0; i < len; ++i)
285 h = (h << 5) - h + arr [i];
287 return h;
290 public CharArrayHashtable (int len)
292 this.len = len;
293 comparer = new ArrComparer (len);
297 struct Pair {
298 public object First;
299 public object Second;
301 public Pair (object f, object s)
303 First = f;
304 Second = s;
308 /// <summary>
309 /// This is a wrapper around StreamReader which is seekable.
310 /// </summary>
311 public class SeekableStreamReader
313 public SeekableStreamReader (StreamReader reader)
315 this.reader = reader;
316 this.buffer = new char [DefaultCacheSize];
318 // Compute the preamble size
320 // Let the StreamWriter autodetect the encoder
321 reader.Peek ();
323 reader.BaseStream.Position = 0;
324 Encoding enc = reader.CurrentEncoding;
325 // First of all, get at least a char
327 byte[] auxb = new byte [50];
328 int num_bytes = 0;
329 int num_chars = 0;
330 int br = 0;
331 do {
332 br = reader.BaseStream.Read (auxb, num_bytes, auxb.Length - num_bytes);
333 num_bytes += br;
334 num_chars = enc.GetCharCount (auxb, 0, num_bytes);
336 while (num_chars == 0 && br > 0);
338 if (num_chars != 0)
340 // Now, check which bytes at the beginning have no effect in the
341 // char count
343 int p = 0;
344 while (enc.GetCharCount (auxb, p, num_bytes-p) >= num_chars)
345 p++;
347 preamble_size = p - 1;
348 reader.BaseStream.Position = 0;
349 reader.DiscardBufferedData ();
351 buffer_start = preamble_size;
355 public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)
356 : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks))
359 StreamReader reader;
361 private const int DefaultCacheSize = 1024;
363 char[] buffer;
364 int buffer_start; // in bytes
365 int buffer_size; // in bytes
366 int char_count; // count buffer[] valid characters
367 int pos; // index into buffer[]
368 int preamble_size;
370 /// <remarks>
371 /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
372 // always reports the correct position and if it's modified, it also takes care of the buffered data.
373 /// </remarks>
374 public int Position {
375 get {
376 return buffer_start + reader.CurrentEncoding.GetByteCount (buffer, 0, pos);
379 set {
380 // This one is easy: we're modifying the position within our current
381 // buffer.
382 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
383 int byte_offset = value - buffer_start;
384 pos = byte_offset;
385 // encoded characters can take more than 1 byte length
386 while (reader.CurrentEncoding.GetByteCount (buffer, 0, pos) > byte_offset)
387 pos--;
389 return;
392 if (value == 0) // Skip preamble
393 value = preamble_size;
395 // Ok, now we need to seek.
396 reader.DiscardBufferedData ();
397 reader.BaseStream.Position = buffer_start = value;
398 char_count = buffer_size = pos = 0;
402 private bool ReadBuffer ()
404 pos = 0;
405 buffer_start += buffer_size;
406 char_count = reader.Read (buffer, 0, buffer.Length);
407 buffer_size = reader.CurrentEncoding.GetByteCount (buffer, 0, char_count);
408 return buffer_size > 0;
411 public int Peek ()
413 if ((pos >= char_count) && !ReadBuffer ())
414 return -1;
416 return buffer [pos];
419 public int Read ()
421 if ((pos >= char_count) && !ReadBuffer ())
422 return -1;
424 return buffer [pos++];
428 public class DoubleHash {
429 const int DEFAULT_INITIAL_BUCKETS = 100;
431 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
433 public DoubleHash (int size)
435 count = size;
436 buckets = new Entry [size];
439 int count;
440 Entry [] buckets;
441 int size = 0;
443 class Entry {
444 public object key1;
445 public object key2;
446 public int hash;
447 public object value;
448 public Entry next;
450 public Entry (object key1, object key2, int hash, object value, Entry next)
452 this.key1 = key1;
453 this.key2 = key2;
454 this.hash = hash;
455 this.next = next;
456 this.value = value;
460 public bool Lookup (object a, object b, out object res)
462 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
464 for (Entry e = buckets [h % count]; e != null; e = e.next) {
465 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
466 res = e.value;
467 return true;
470 res = null;
471 return false;
474 public void Insert (object a, object b, object value)
476 // Is it an existing one?
478 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
480 for (Entry e = buckets [h % count]; e != null; e = e.next) {
481 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
482 e.value = value;
485 int bucket = h % count;
486 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
488 // Grow whenever we double in size
489 if (size++ == count) {
490 count <<= 1;
491 count ++;
493 Entry [] newBuckets = new Entry [count];
494 foreach (Entry root in buckets) {
495 Entry e = root;
496 while (e != null) {
497 int newLoc = e.hash % count;
498 Entry n = e.next;
499 e.next = newBuckets [newLoc];
500 newBuckets [newLoc] = e;
501 e = n;
505 buckets = newBuckets;