System.Drawing: added email to icon and test file headers
[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                 StreamReader reader;
140                 Stream stream;
141
142                 static char[] buffer;
143                 int read_ahead_length;  // the length of read buffer
144                 int buffer_start;       // in chars
145                 int char_count;         // count of filled characters in buffer[]
146                 int pos;                // index into buffer[]
147
148                 public SeekableStreamReader (Stream stream, Encoding encoding)
149                 {
150                         this.stream = stream;
151
152                         const int default_read_ahead = 2048;
153                         InitializeStream (default_read_ahead);
154                         reader = new StreamReader (stream, encoding, true);
155                 }
156
157                 public void Dispose ()
158                 {
159                         // Needed to release stream reader buffers
160                         reader.Dispose ();
161                 }
162
163                 void InitializeStream (int read_length_inc)
164                 {
165                         read_ahead_length += read_length_inc;
166
167                         int required_buffer_size = read_ahead_length * 2;
168
169                         if (buffer == null || buffer.Length < required_buffer_size)
170                                 buffer = new char [required_buffer_size];
171
172                         stream.Position = 0;
173                         buffer_start = char_count = pos = 0;
174                 }
175
176                 /// <remarks>
177                 ///   This value corresponds to the current position in a stream of characters.
178                 ///   The StreamReader hides its manipulation of the underlying byte stream and all
179                 ///   character set/decoding issues.  Thus, we cannot use this position to guess at
180                 ///   the corresponding position in the underlying byte stream even though there is
181                 ///   a correlation between them.
182                 /// </remarks>
183                 public int Position {
184                         get {
185                                 return buffer_start + pos;
186                         }
187
188                         set {
189                                 //
190                                 // If the lookahead was too small, re-read from the beginning. Increase the buffer size while we're at it
191                                 // This should never happen until we are parsing some weird source code
192                                 //
193                                 if (value < buffer_start) {
194                                         InitializeStream (read_ahead_length);
195
196                                         //
197                                         // Discard buffer data after underlying stream changed position
198                                         // Cannot use handy reader.DiscardBufferedData () because it for
199                                         // some strange reason resets encoding as well
200                                         //
201                                         reader = new StreamReader (stream, reader.CurrentEncoding, true);
202                                 }
203
204                                 while (value > buffer_start + char_count) {
205                                         pos = char_count;
206                                         if (!ReadBuffer ())
207                                                 throw new InternalErrorException ("Seek beyond end of file: " + (buffer_start + char_count - value));
208                                 }
209
210                                 pos = value - buffer_start;
211                         }
212                 }
213
214                 bool ReadBuffer ()
215                 {
216                         int slack = buffer.Length - char_count;
217
218                         //
219                         // read_ahead_length is only half of the buffer to deal with
220                         // reads ahead and moves back without re-reading whole buffer
221                         //
222                         if (slack <= read_ahead_length) {
223                                 //
224                                 // shift the buffer to make room for read_ahead_length number of characters
225                                 //
226                                 int shift = read_ahead_length - slack;
227                                 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
228
229                                 // Update all counters
230                                 pos -= shift;
231                                 char_count -= shift;
232                                 buffer_start += shift;
233                                 slack += shift;
234                         }
235
236                         char_count += reader.Read (buffer, char_count, slack);
237
238                         return pos < char_count;
239                 }
240
241                 public char[] ReadChars (int fromPosition, int toPosition)
242                 {
243                         char[] chars = new char[toPosition - fromPosition];
244                         if (buffer_start <= fromPosition && toPosition <= buffer_start + buffer.Length) {
245                                 Array.Copy (buffer, fromPosition - buffer_start, chars, 0, chars.Length);
246                         } else {
247                                 throw new NotImplementedException ();
248                         }
249
250                         return chars;
251                 }
252
253                 public int Peek ()
254                 {
255                         if ((pos >= char_count) && !ReadBuffer ())
256                                 return -1;
257
258                         return buffer [pos];
259                 }
260
261                 public int Read ()
262                 {
263                         if ((pos >= char_count) && !ReadBuffer ())
264                                 return -1;
265
266                         return buffer [pos++];
267                 }
268         }
269
270         public class UnixUtils {
271                 [System.Runtime.InteropServices.DllImport ("libc", EntryPoint="isatty")]
272                 extern static int _isatty (int fd);
273                         
274                 public static bool isatty (int fd)
275                 {
276                         try {
277                                 return _isatty (fd) == 1;
278                         } catch {
279                                 return false;
280                         }
281                 }
282         }
283
284         /// <summary>
285         ///   An exception used to terminate the compiler resolution phase and provide completions
286         /// </summary>
287         /// <remarks>
288         ///   This is thrown when we want to return the completions or
289         ///   terminate the completion process by AST nodes used in
290         ///   the completion process.
291         /// </remarks>
292         public class CompletionResult : Exception {
293                 string [] result;
294                 string base_text;
295                 
296                 public CompletionResult (string base_text, string [] res)
297                 {
298                         if (base_text == null)
299                                 throw new ArgumentNullException ("base_text");
300                         this.base_text = base_text;
301
302                         result = res;
303                         Array.Sort (result);
304                 }
305
306                 public string [] Result {
307                         get {
308                                 return result;
309                         }
310                 }
311
312                 public string BaseText {
313                         get {
314                                 return base_text;
315                         }
316                 }
317         }
318 }