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
);
78 /// This is an arbitrarily seekable StreamReader wrapper.
80 /// It uses a self-tuning buffer to cache the seekable data,
81 /// but if the seek is too far, it may read the underly
82 /// stream all over from the beginning.
84 public class SeekableStreamReader
: IDisposable
86 const int buffer_read_length_spans
= 3;
92 int average_read_length
;
93 int buffer_start
; // in chars
94 int char_count
; // count buffer[] valid characters
95 int pos
; // index into buffer[]
97 public SeekableStreamReader (Stream stream
, Encoding encoding
)
101 const int default_average_read_length
= 1024;
102 InitializeStream (default_average_read_length
);
103 reader
= new StreamReader (stream
, encoding
, true);
106 public void Dispose ()
108 // Needed to release stream reader buffers
112 void InitializeStream (int read_length_inc
)
114 average_read_length
+= read_length_inc
;
116 int required_buffer_size
= average_read_length
* buffer_read_length_spans
;
117 if (buffer
== null || buffer
.Length
< required_buffer_size
)
118 buffer
= new char [required_buffer_size
];
121 buffer_start
= char_count
= pos
= 0;
125 /// This value corresponds to the current position in a stream of characters.
126 /// The StreamReader hides its manipulation of the underlying byte stream and all
127 /// character set/decoding issues. Thus, we cannot use this position to guess at
128 /// the corresponding position in the underlying byte stream even though there is
129 /// a correlation between them.
131 public int Position
{
132 get { return buffer_start + pos; }
135 // If the lookahead was too small, re-read from the beginning. Increase the buffer size while we're at it
136 if (value < buffer_start
)
137 InitializeStream (average_read_length
/ 2);
139 while (value > buffer_start
+ char_count
) {
142 throw new InternalErrorException ("Seek beyond end of file: " + (buffer_start
+ char_count
- value));
145 pos
= value - buffer_start
;
149 private bool ReadBuffer ()
151 int slack
= buffer
.Length
- char_count
;
152 if (slack
<= average_read_length
/ 2) {
153 // shift the buffer to make room for average_read_length number of characters
154 int shift
= average_read_length
- slack
;
155 Array
.Copy (buffer
, shift
, buffer
, 0, char_count
- shift
);
158 buffer_start
+= shift
;
159 slack
+= shift
; // slack == average_read_length
162 char_count
+= reader
.Read (buffer
, char_count
, slack
);
164 return pos
< char_count
;
169 if ((pos
>= char_count
) && !ReadBuffer ())
177 if ((pos
>= char_count
) && !ReadBuffer ())
180 return buffer
[pos
++];
184 public class DoubleHash
{
185 const int DEFAULT_INITIAL_BUCKETS
= 100;
187 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS
) {}
189 public DoubleHash (int size
)
192 buckets
= new Entry
[size
];
206 public Entry (object key1
, object key2
, int hash
, object value, Entry next
)
216 public bool Lookup (object a
, object b
, out object res
)
218 int h
= (a
.GetHashCode () ^ b
.GetHashCode ()) & 0x7FFFFFFF;
220 for (Entry e
= buckets
[h
% count
]; e
!= null; e
= e
.next
) {
221 if (e
.hash
== h
&& e
.key1
.Equals (a
) && e
.key2
.Equals (b
)) {
230 public void Insert (object a
, object b
, object value)
232 // Is it an existing one?
234 int h
= (a
.GetHashCode () ^ b
.GetHashCode ()) & 0x7FFFFFFF;
236 for (Entry e
= buckets
[h
% count
]; e
!= null; e
= e
.next
) {
237 if (e
.hash
== h
&& e
.key1
.Equals (a
) && e
.key2
.Equals (b
))
241 int bucket
= h
% count
;
242 buckets
[bucket
] = new Entry (a
, b
, h
, value, buckets
[bucket
]);
244 // Grow whenever we double in size
245 if (size
++ == count
) {
249 Entry
[] newBuckets
= new Entry
[count
];
250 foreach (Entry root
in buckets
) {
253 int newLoc
= e
.hash
% count
;
255 e
.next
= newBuckets
[newLoc
];
256 newBuckets
[newLoc
] = e
;
261 buckets
= newBuckets
;
266 public class UnixUtils
{
267 [System
.Runtime
.InteropServices
.DllImport ("libc", EntryPoint
="isatty")]
268 extern static int _isatty (int fd
);
270 public static bool isatty (int fd
)
273 return _isatty (fd
) == 1;
281 /// An exception used to terminate the compiler resolution phase and provide completions
284 /// This is thrown when we want to return the completions or
285 /// terminate the completion process by AST nodes used in
286 /// the completion process.
288 public class CompletionResult
: Exception
{
292 public CompletionResult (string base_text
, string [] res
)
294 if (base_text
== null)
295 throw new ArgumentNullException ("base_text");
296 this.base_text
= base_text
;
302 public string [] Result
{
308 public string BaseText
{