Merge pull request #335 from robwilkens/DataGridBugs1
[mono.git] / mcs / mcs / support.cs
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 //   Marek Safar (marek.safar@gmail.com)
8 //
9 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2009 Novell, Inc
11 // Copyright 2011 Xamarin Inc
12 //
13
14 using System;
15 using System.IO;
16 using System.Text;
17 using System.Collections.Generic;
18
19 namespace Mono.CSharp {
20
21         sealed class ReferenceEquality<T> : IEqualityComparer<T> where T : class
22         {
23                 public static readonly IEqualityComparer<T> Default = new ReferenceEquality<T> ();
24
25                 private ReferenceEquality ()
26                 {
27                 }
28
29                 public bool Equals (T x, T y)
30                 {
31                         return ReferenceEquals (x, y);
32                 }
33
34                 public int GetHashCode (T obj)
35                 {
36                         return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode (obj);
37                 }
38         }
39 #if !NET_4_0 && !MONODROID
40         public class Tuple<T1, T2> : IEquatable<Tuple<T1, T2>>
41         {
42                 public Tuple (T1 item1, T2 item2)
43                 {
44                         Item1 = item1;
45                         Item2 = item2;
46                 }
47
48                 public T1 Item1 { get; private set; }
49                 public T2 Item2 { get; private set; }
50
51                 public override int GetHashCode ()
52                 {
53                         return Item1.GetHashCode () ^ Item2.GetHashCode ();
54                 }
55
56                 #region IEquatable<Tuple<T1,T2>> Members
57
58                 public bool Equals (Tuple<T1, T2> other)
59                 {
60                         return EqualityComparer<T1>.Default.Equals (Item1, other.Item1) &&
61                                 EqualityComparer<T2>.Default.Equals (Item2, other.Item2);
62                 }
63
64                 #endregion
65         }
66
67         public class Tuple<T1, T2, T3> : IEquatable<Tuple<T1, T2, T3>>
68         {
69                 public Tuple (T1 item1, T2 item2, T3 item3)
70                 {
71                         Item1 = item1;
72                         Item2 = item2;
73                         Item3 = item3;
74                 }
75
76                 public T1 Item1 { get; private set; }
77                 public T2 Item2 { get; private set; }
78                 public T3 Item3 { get; private set; }
79
80                 public override int GetHashCode ()
81                 {
82                         return Item1.GetHashCode () ^ Item2.GetHashCode () ^ Item3.GetHashCode ();
83                 }
84
85                 #region IEquatable<Tuple<T1,T2>> Members
86
87                 public bool Equals (Tuple<T1, T2, T3> other)
88                 {
89                         return EqualityComparer<T1>.Default.Equals (Item1, other.Item1) &&
90                                 EqualityComparer<T2>.Default.Equals (Item2, other.Item2) &&
91                                 EqualityComparer<T3>.Default.Equals (Item3, other.Item3);
92                 }
93
94                 #endregion
95         }
96
97         static class Tuple
98         {
99                 public static Tuple<T1, T2> Create<T1, T2> (T1 item1, T2 item2)
100                 {
101                         return new Tuple<T1, T2> (item1, item2);
102                 }
103
104                 public static Tuple<T1, T2, T3> Create<T1, T2, T3> (T1 item1, T2 item2, T3 item3)
105                 {
106                         return new Tuple<T1, T2, T3> (item1, item2, item3);
107                 }
108         }
109 #endif
110
111         static class ArrayComparer
112         {
113                 public static bool IsEqual<T> (T[] array1, T[] array2)
114                 {
115                         if (array1 == null || array2 == null)
116                                 return array1 == array2;
117
118                         var eq = EqualityComparer<T>.Default;
119
120                         for (int i = 0; i < array1.Length; ++i) {
121                                 if (!eq.Equals (array1[i], array2[i])) {
122                                         return false;
123                                 }
124                         }
125
126                         return true;
127                 }
128         }
129
130         /// <summary>
131         ///   This is an arbitrarily seekable StreamReader wrapper.
132         ///
133         ///   It uses a self-tuning buffer to cache the seekable data,
134         ///   but if the seek is too far, it may read the underly
135         ///   stream all over from the beginning.
136         /// </summary>
137         public class SeekableStreamReader : IDisposable
138         {
139                 public const int DefaultReadAheadSize = 2048;
140
141                 StreamReader reader;
142                 Stream stream;
143
144                 char[] buffer;
145                 int read_ahead_length;  // the length of read buffer
146                 int buffer_start;       // in chars
147                 int char_count;         // count of filled characters in buffer[]
148                 int pos;                // index into buffer[]
149
150                 public SeekableStreamReader (Stream stream, Encoding encoding, char[] sharedBuffer = null)
151                 {
152                         this.stream = stream;
153                         this.buffer = sharedBuffer;
154
155                         InitializeStream (DefaultReadAheadSize);
156                         reader = new StreamReader (stream, encoding, true);
157                 }
158
159                 public void Dispose ()
160                 {
161                         // Needed to release stream reader buffers
162                         reader.Dispose ();
163                 }
164
165                 void InitializeStream (int read_length_inc)
166                 {
167                         read_ahead_length += read_length_inc;
168
169                         int required_buffer_size = read_ahead_length * 2;
170
171                         if (buffer == null || buffer.Length < required_buffer_size)
172                                 buffer = new char [required_buffer_size];
173
174                         stream.Position = 0;
175                         buffer_start = char_count = pos = 0;
176                 }
177
178                 /// <remarks>
179                 ///   This value corresponds to the current position in a stream of characters.
180                 ///   The StreamReader hides its manipulation of the underlying byte stream and all
181                 ///   character set/decoding issues.  Thus, we cannot use this position to guess at
182                 ///   the corresponding position in the underlying byte stream even though there is
183                 ///   a correlation between them.
184                 /// </remarks>
185                 public int Position {
186                         get {
187                                 return buffer_start + pos;
188                         }
189
190                         set {
191                                 //
192                                 // If the lookahead was too small, re-read from the beginning. Increase the buffer size while we're at it
193                                 // This should never happen until we are parsing some weird source code
194                                 //
195                                 if (value < buffer_start) {
196                                         InitializeStream (read_ahead_length);
197
198                                         //
199                                         // Discard buffer data after underlying stream changed position
200                                         // Cannot use handy reader.DiscardBufferedData () because it for
201                                         // some strange reason resets encoding as well
202                                         //
203                                         reader = new StreamReader (stream, reader.CurrentEncoding, true);
204                                 }
205
206                                 while (value > buffer_start + char_count) {
207                                         pos = char_count;
208                                         if (!ReadBuffer ())
209                                                 throw new InternalErrorException ("Seek beyond end of file: " + (buffer_start + char_count - value));
210                                 }
211
212                                 pos = value - buffer_start;
213                         }
214                 }
215
216                 bool ReadBuffer ()
217                 {
218                         int slack = buffer.Length - char_count;
219
220                         //
221                         // read_ahead_length is only half of the buffer to deal with
222                         // reads ahead and moves back without re-reading whole buffer
223                         //
224                         if (slack <= read_ahead_length) {
225                                 //
226                                 // shift the buffer to make room for read_ahead_length number of characters
227                                 //
228                                 int shift = read_ahead_length - slack;
229                                 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
230
231                                 // Update all counters
232                                 pos -= shift;
233                                 char_count -= shift;
234                                 buffer_start += shift;
235                                 slack += shift;
236                         }
237
238                         char_count += reader.Read (buffer, char_count, slack);
239
240                         return pos < char_count;
241                 }
242
243                 public char[] ReadChars (int fromPosition, int toPosition)
244                 {
245                         char[] chars = new char[toPosition - fromPosition];
246                         if (buffer_start <= fromPosition && toPosition <= buffer_start + buffer.Length) {
247                                 Array.Copy (buffer, fromPosition - buffer_start, chars, 0, chars.Length);
248                         } else {
249                                 throw new NotImplementedException ();
250                         }
251
252                         return chars;
253                 }
254
255                 public int Peek ()
256                 {
257                         if ((pos >= char_count) && !ReadBuffer ())
258                                 return -1;
259
260                         return buffer [pos];
261                 }
262
263                 public int Read ()
264                 {
265                         if ((pos >= char_count) && !ReadBuffer ())
266                                 return -1;
267
268                         return buffer [pos++];
269                 }
270         }
271
272         public class UnixUtils {
273                 [System.Runtime.InteropServices.DllImport ("libc", EntryPoint="isatty")]
274                 extern static int _isatty (int fd);
275                         
276                 public static bool isatty (int fd)
277                 {
278                         try {
279                                 return _isatty (fd) == 1;
280                         } catch {
281                                 return false;
282                         }
283                 }
284         }
285
286         /// <summary>
287         ///   An exception used to terminate the compiler resolution phase and provide completions
288         /// </summary>
289         /// <remarks>
290         ///   This is thrown when we want to return the completions or
291         ///   terminate the completion process by AST nodes used in
292         ///   the completion process.
293         /// </remarks>
294         public class CompletionResult : Exception {
295                 string [] result;
296                 string base_text;
297                 
298                 public CompletionResult (string base_text, string [] res)
299                 {
300                         if (base_text == null)
301                                 throw new ArgumentNullException ("base_text");
302                         this.base_text = base_text;
303
304                         result = res;
305                         Array.Sort (result);
306                 }
307
308                 public string [] Result {
309                         get {
310                                 return result;
311                         }
312                 }
313
314                 public string BaseText {
315                         get {
316                                 return base_text;
317                         }
318                 }
319         }
320 }