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;
32 bool is_varargs
= false;
34 public ReflectionParameters (MethodBase mb
)
38 ParameterInfo
[] pi
= mb
.GetParameters ();
39 is_varargs
= (mb
.CallingConvention
& CallingConventions
.VarArgs
) != 0;
42 int count
= pi
.Length
-1;
45 attrs
= pi
[count
].GetCustomAttributes (TypeManager
.param_array_type
, true);
50 if (attrs
.Length
== 0)
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
;
64 Type t
= pi
[pos
].ParameterType
;
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
)
80 public string ParameterDesc (int pos
)
82 if (is_varargs
&& pos
>= pi
.Length
)
85 StringBuilder sb
= new StringBuilder ();
90 Type partype
= ParameterType (pos
);
92 partype
= TypeManager
.GetElementType (partype
);
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
)
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
;
119 if ((pi
[pos
].Attributes
& ParameterAttributes
.Out
) != 0)
120 return Parameter
.Modifier
.ISBYREF
| Parameter
.Modifier
.OUT
;
122 return Parameter
.Modifier
.ISBYREF
| Parameter
.Modifier
.REF
;
125 return Parameter
.Modifier
.NONE
;
130 return is_varargs
? pi
.Length
+ 1 : pi
.Length
;
136 public class InternalParameters
: ParameterData
{
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)
153 count
= param_types
.Length
;
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
;
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)
182 return GetParameter (pos
).ExternalType ();
186 public string ParameterName (int pos
)
188 if (has_varargs
&& pos
>= count
)
191 return GetParameter (pos
).Name
;
194 public string ParameterDesc (int pos
)
196 if (has_varargs
&& pos
>= count
)
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)
208 else if ((p
.ModFlags
& Parameter
.Modifier
.OUT
) != 0)
210 else if (p
.ModFlags
== Parameter
.Modifier
.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
;
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
)
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
{
261 public ArrComparer (int 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
)
279 protected override int GetHash (Object key
)
281 char[] arr
= (char[])key
;
284 for (int i
= 0; i
< len
; ++i
)
285 h
= (h
<< 5) - h
+ arr
[i
];
290 public CharArrayHashtable (int len
)
293 comparer
= new ArrComparer (len
);
299 public object Second
;
301 public Pair (object f
, object s
)
309 /// This is a wrapper around StreamReader which is seekable.
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
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];
332 br
= reader
.BaseStream
.Read (auxb
, num_bytes
, auxb
.Length
- num_bytes
);
334 num_chars
= enc
.GetCharCount (auxb
, 0, num_bytes
);
336 while (num_chars
== 0 && br
> 0);
340 // Now, check which bytes at the beginning have no effect in the
344 while (enc
.GetCharCount (auxb
, p
, num_bytes
-p
) >= num_chars
)
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
))
361 private const int DefaultCacheSize
= 1024;
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[]
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.
374 public int Position
{
376 return buffer_start
+ reader
.CurrentEncoding
.GetByteCount (buffer
, 0, pos
);
380 // This one is easy: we're modifying the position within our current
382 if ((value >= buffer_start
) && (value < buffer_start
+ buffer_size
)) {
383 int byte_offset
= value - buffer_start
;
385 // encoded characters can take more than 1 byte length
386 while (reader
.CurrentEncoding
.GetByteCount (buffer
, 0, pos
) > byte_offset
)
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 ()
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;
413 if ((pos
>= char_count
) && !ReadBuffer ())
421 if ((pos
>= char_count
) && !ReadBuffer ())
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
)
436 buckets
= new Entry
[size
];
450 public Entry (object key1
, object key2
, int hash
, object value, Entry next
)
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
)) {
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
))
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
) {
493 Entry
[] newBuckets
= new Entry
[count
];
494 foreach (Entry root
in buckets
) {
497 int newLoc
= e
.hash
% count
;
499 e
.next
= newBuckets
[newLoc
];
500 newBuckets
[newLoc
] = e
;
505 buckets
= newBuckets
;