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;
38 public ReflectionParameters (MethodBase mb
)
42 ParameterInfo
[] pi
= mb
.GetParameters ();
43 is_varargs
= (mb
.CallingConvention
& CallingConventions
.VarArgs
) != 0;
46 int count
= pi
.Length
-1;
49 types
= Type
.EmptyTypes
;
51 types
= new Type
[pi
.Length
];
52 for (int i
= 0; i
< pi
.Length
; i
++)
53 types
[i
] = pi
[i
].ParameterType
;
57 attrs
= pi
[count
].GetCustomAttributes (TypeManager
.param_array_type
, true);
62 if (attrs
.Length
== 0)
65 last_arg_is_params
= true;
69 public string GetSignatureForError ()
71 StringBuilder sb
= new StringBuilder ("(");
72 for (int i
= 0; i
< pi
.Length
; ++i
) {
75 sb
.Append (ParameterDesc (i
));
80 sb
.Append ("__arglist");
83 return sb
.ToString ();
86 public Type
ParameterType (int pos
)
88 if (last_arg_is_params
&& pos
>= pi
.Length
- 1)
89 return pi
[pi
.Length
- 1].ParameterType
;
90 else if (is_varargs
&& pos
>= pi
.Length
)
91 return TypeManager
.runtime_argument_handle_type
;
93 Type t
= pi
[pos
].ParameterType
;
99 public string ParameterName (int pos
)
101 if (last_arg_is_params
&& pos
>= pi
.Length
- 1)
102 return pi
[pi
.Length
- 1].Name
;
103 else if (is_varargs
&& pos
>= pi
.Length
)
106 return pi
[pos
].Name
;
109 public string ParameterDesc (int pos
)
111 if (is_varargs
&& pos
>= pi
.Length
)
114 StringBuilder sb
= new StringBuilder ();
119 Type partype
= ParameterType (pos
);
120 if (partype
.IsByRef
){
121 partype
= TypeManager
.GetElementType (partype
);
128 if (pos
>= pi
.Length
- 1 && last_arg_is_params
)
129 sb
.Append ("params ");
131 sb
.Append (TypeManager
.CSharpName (partype
).Replace ("&", ""));
133 return sb
.ToString ();
137 public Parameter
.Modifier
ParameterModifier (int pos
)
139 if (last_arg_is_params
&& pos
>= pi
.Length
- 1)
140 return Parameter
.Modifier
.PARAMS
;
141 else if (is_varargs
&& pos
>= pi
.Length
)
142 return Parameter
.Modifier
.ARGLIST
;
144 Type t
= pi
[pos
].ParameterType
;
146 if ((pi
[pos
].Attributes
& (ParameterAttributes
.Out
|ParameterAttributes
.In
)) == ParameterAttributes
.Out
)
147 return Parameter
.Modifier
.OUT
;
149 return Parameter
.Modifier
.REF
;
152 return Parameter
.Modifier
.NONE
;
157 return is_varargs
? pi
.Length
+ 1 : pi
.Length
;
161 public bool HasParams
{
163 return this.last_arg_is_params
;
167 public Type
[] Types
{
175 class PtrHashtable
: Hashtable
{
176 sealed class PtrComparer
: IComparer
{
177 private PtrComparer () {}
179 public static PtrComparer Instance
= new PtrComparer ();
181 public int Compare (object x
, object y
)
190 public PtrHashtable ()
192 comparer
= PtrComparer
.Instance
;
197 * Hashtable whose keys are character arrays with the same length
199 class CharArrayHashtable
: Hashtable
{
200 sealed class ArrComparer
: IComparer
{
203 public ArrComparer (int len
) {
207 public int Compare (object x
, object y
)
209 char[] a
= (char[])x
;
210 char[] b
= (char[])y
;
212 for (int i
= 0; i
< len
; ++i
)
221 protected override int GetHash (Object key
)
223 char[] arr
= (char[])key
;
226 for (int i
= 0; i
< len
; ++i
)
227 h
= (h
<< 5) - h
+ arr
[i
];
232 public CharArrayHashtable (int len
)
235 comparer
= new ArrComparer (len
);
241 public object Second
;
243 public Pair (object f
, object s
)
251 /// This is a wrapper around StreamReader which is seekable backwards
252 /// within a window of around 2048 chars.
254 public class SeekableStreamReader
256 public SeekableStreamReader (StreamReader reader
)
258 this.reader
= reader
;
259 this.buffer
= new char [AverageReadLength
* 3];
261 // Let the StreamWriter autodetect the encoder
265 public SeekableStreamReader (Stream stream
, Encoding encoding
)
266 : this (new StreamReader (stream
, encoding
, true))
271 private const int AverageReadLength
= 1024;
274 int buffer_start
; // in chars
275 int char_count
; // count buffer[] valid characters
276 int pos
; // index into buffer[]
279 /// This value corresponds to the current position in a stream of characters.
280 /// The StreamReader hides its manipulation of the underlying byte stream and all
281 /// character set/decoding issues. Thus, we cannot use this position to guess at
282 /// the corresponding position in the underlying byte stream even though there is
283 /// a correlation between them.
285 public int Position
{
286 get { return buffer_start + pos; }
289 if (value < buffer_start
|| value > buffer_start
+ char_count
)
290 throw new InternalErrorException ("can't seek that far back: " + (pos
- value));
291 pos
= value - buffer_start
;
295 private bool ReadBuffer ()
297 int slack
= buffer
.Length
- char_count
;
298 if (slack
<= AverageReadLength
/ 2) {
299 // shift the buffer to make room for AverageReadLength number of characters
300 int shift
= AverageReadLength
- slack
;
301 Array
.Copy (buffer
, shift
, buffer
, 0, char_count
- shift
);
304 buffer_start
+= shift
;
305 slack
+= shift
; // slack == AverageReadLength
308 int chars_read
= reader
.Read (buffer
, char_count
, slack
);
309 char_count
+= chars_read
;
311 return pos
< char_count
;
316 if ((pos
>= char_count
) && !ReadBuffer ())
324 if ((pos
>= char_count
) && !ReadBuffer ())
327 return buffer
[pos
++];
331 public class DoubleHash
{
332 const int DEFAULT_INITIAL_BUCKETS
= 100;
334 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS
) {}
336 public DoubleHash (int size
)
339 buckets
= new Entry
[size
];
353 public Entry (object key1
, object key2
, int hash
, object value, Entry next
)
363 public bool Lookup (object a
, object b
, out object res
)
365 int h
= (a
.GetHashCode () ^ b
.GetHashCode ()) & 0x7FFFFFFF;
367 for (Entry e
= buckets
[h
% count
]; e
!= null; e
= e
.next
) {
368 if (e
.hash
== h
&& e
.key1
.Equals (a
) && e
.key2
.Equals (b
)) {
377 public void Insert (object a
, object b
, object value)
379 // Is it an existing one?
381 int h
= (a
.GetHashCode () ^ b
.GetHashCode ()) & 0x7FFFFFFF;
383 for (Entry e
= buckets
[h
% count
]; e
!= null; e
= e
.next
) {
384 if (e
.hash
== h
&& e
.key1
.Equals (a
) && e
.key2
.Equals (b
))
388 int bucket
= h
% count
;
389 buckets
[bucket
] = new Entry (a
, b
, h
, value, buckets
[bucket
]);
391 // Grow whenever we double in size
392 if (size
++ == count
) {
396 Entry
[] newBuckets
= new Entry
[count
];
397 foreach (Entry root
in buckets
) {
400 int newLoc
= e
.hash
% count
;
402 e
.next
= newBuckets
[newLoc
];
403 newBuckets
[newLoc
] = e
;
408 buckets
= newBuckets
;