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