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)
7 // Marek Safar (marek.safar@gmail.com)
9 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2009 Novell, Inc
16 using System
.Reflection
;
17 using System
.Reflection
.Emit
;
18 using System
.Globalization
;
19 using System
.Collections
.Generic
;
21 namespace Mono
.CSharp
{
23 sealed class ReferenceEquality
<T
> : IEqualityComparer
<T
> where T
: class
25 public static readonly IEqualityComparer
<T
> Default
= new ReferenceEquality
<T
> ();
27 private ReferenceEquality ()
31 public bool Equals (T x
, T y
)
33 return ReferenceEquals (x
, y
);
36 public int GetHashCode (T obj
)
38 return System
.Runtime
.CompilerServices
.RuntimeHelpers
.GetHashCode (obj
);
42 class Tuple
<T1
, T2
> : IEquatable
<Tuple
<T1
, T2
>>
44 public Tuple (T1 item1
, T2 item2
)
50 public T1 Item1 { get; private set; }
51 public T2 Item2 { get; private set; }
53 public override int GetHashCode ()
55 return Item1
.GetHashCode () ^ Item2
.GetHashCode ();
58 #region IEquatable<Tuple<T1,T2>> Members
60 public bool Equals (Tuple
<T1
, T2
> other
)
62 return EqualityComparer
<T1
>.Default
.Equals (Item1
, other
.Item1
) &&
63 EqualityComparer
<T2
>.Default
.Equals (Item2
, other
.Item2
);
71 public static Tuple
<T1
, T2
> Create
<T1
, T2
> (T1 item1
, T2 item2
)
73 return new Tuple
<T1
, T2
> (item1
, item2
);
77 public class Accessors
{
78 public Accessor get_or_add
;
79 public Accessor set_or_remove
;
81 // was 'set' declared before 'get'? was 'remove' declared before 'add'?
82 public bool declared_in_reverse
;
84 public Accessors (Accessor get_or_add
, Accessor set_or_remove
)
86 this.get_or_add
= get_or_add
;
87 this.set_or_remove
= set_or_remove
;
92 /// This is an arbitrarily seekable StreamReader wrapper.
94 /// It uses a self-tuning buffer to cache the seekable data,
95 /// but if the seek is too far, it may read the underly
96 /// stream all over from the beginning.
98 public class SeekableStreamReader
: IDisposable
100 const int buffer_read_length_spans
= 3;
105 static char[] buffer
;
106 int average_read_length
;
107 int buffer_start
; // in chars
108 int char_count
; // count buffer[] valid characters
109 int pos
; // index into buffer[]
111 public SeekableStreamReader (Stream stream
, Encoding encoding
)
113 this.stream
= stream
;
115 const int default_average_read_length
= 1024;
116 InitializeStream (default_average_read_length
);
117 reader
= new StreamReader (stream
, encoding
, true);
120 public void Dispose ()
122 // Needed to release stream reader buffers
126 void InitializeStream (int read_length_inc
)
128 average_read_length
+= read_length_inc
;
130 int required_buffer_size
= average_read_length
* buffer_read_length_spans
;
131 if (buffer
== null || buffer
.Length
< required_buffer_size
)
132 buffer
= new char [required_buffer_size
];
135 buffer_start
= char_count
= pos
= 0;
139 /// This value corresponds to the current position in a stream of characters.
140 /// The StreamReader hides its manipulation of the underlying byte stream and all
141 /// character set/decoding issues. Thus, we cannot use this position to guess at
142 /// the corresponding position in the underlying byte stream even though there is
143 /// a correlation between them.
145 public int Position
{
146 get { return buffer_start + pos; }
149 // If the lookahead was too small, re-read from the beginning. Increase the buffer size while we're at it
150 if (value < buffer_start
)
151 InitializeStream (average_read_length
/ 2);
153 while (value > buffer_start
+ char_count
) {
156 throw new InternalErrorException ("Seek beyond end of file: " + (buffer_start
+ char_count
- value));
159 pos
= value - buffer_start
;
163 private bool ReadBuffer ()
165 int slack
= buffer
.Length
- char_count
;
166 if (slack
<= average_read_length
/ 2) {
167 // shift the buffer to make room for average_read_length number of characters
168 int shift
= average_read_length
- slack
;
169 Array
.Copy (buffer
, shift
, buffer
, 0, char_count
- shift
);
172 buffer_start
+= shift
;
173 slack
+= shift
; // slack == average_read_length
176 char_count
+= reader
.Read (buffer
, char_count
, slack
);
178 return pos
< char_count
;
183 if ((pos
>= char_count
) && !ReadBuffer ())
191 if ((pos
>= char_count
) && !ReadBuffer ())
194 return buffer
[pos
++];
198 public class DoubleHash
{
199 const int DEFAULT_INITIAL_BUCKETS
= 100;
201 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS
) {}
203 public DoubleHash (int size
)
206 buckets
= new Entry
[size
];
220 public Entry (object key1
, object key2
, int hash
, object value, Entry next
)
230 public bool Lookup (object a
, object b
, out object res
)
232 int h
= (a
.GetHashCode () ^ b
.GetHashCode ()) & 0x7FFFFFFF;
234 for (Entry e
= buckets
[h
% count
]; e
!= null; e
= e
.next
) {
235 if (e
.hash
== h
&& e
.key1
.Equals (a
) && e
.key2
.Equals (b
)) {
244 public void Insert (object a
, object b
, object value)
246 // Is it an existing one?
248 int h
= (a
.GetHashCode () ^ b
.GetHashCode ()) & 0x7FFFFFFF;
250 for (Entry e
= buckets
[h
% count
]; e
!= null; e
= e
.next
) {
251 if (e
.hash
== h
&& e
.key1
.Equals (a
) && e
.key2
.Equals (b
))
255 int bucket
= h
% count
;
256 buckets
[bucket
] = new Entry (a
, b
, h
, value, buckets
[bucket
]);
258 // Grow whenever we double in size
259 if (size
++ == count
) {
263 Entry
[] newBuckets
= new Entry
[count
];
264 foreach (Entry root
in buckets
) {
267 int newLoc
= e
.hash
% count
;
269 e
.next
= newBuckets
[newLoc
];
270 newBuckets
[newLoc
] = e
;
275 buckets
= newBuckets
;
280 public class UnixUtils
{
281 [System
.Runtime
.InteropServices
.DllImport ("libc", EntryPoint
="isatty")]
282 extern static int _isatty (int fd
);
284 public static bool isatty (int fd
)
287 return _isatty (fd
) == 1;
295 /// An exception used to terminate the compiler resolution phase and provide completions
298 /// This is thrown when we want to return the completions or
299 /// terminate the completion process by AST nodes used in
300 /// the completion process.
302 public class CompletionResult
: Exception
{
306 public CompletionResult (string base_text
, string [] res
)
308 if (base_text
== null)
309 throw new ArgumentNullException ("base_text");
310 this.base_text
= base_text
;
316 public string [] Result
{
322 public string BaseText
{